When using a 64-bit program System.Data.SQLite is throwing the following EntryPointNotFoundException:
Unable to find an entry point named 'sqlite3_changes_interop' in DLL 'SQLite.Interop.dll'.
Strangely it only occurs if Foreign Keys=True
is specified in the connection string and more importantly only after I display a FolderBrowserDialog
. I was browsing for a folder to display databases to load.
The following code displays the problem:
public Form1()
{
InitializeComponent();
// Exception below if this is displayed
using (var diag = new FolderBrowserDialog())
{
diag.ShowDialog(this);
}
var conn = new SQLiteConnection("data source=':memory:'");
conn.Open(); // Works fine
conn.Close();
// No exception below if displayed here instead
//using (var diag = new FolderBrowserDialog())
//{
// diag.ShowDialog(this);
//}
conn = new SQLiteConnection("data source=':memory:';foreign keys=True");
conn.Open(); // EntryPointNotFoundException thrown here
conn.Close();
}
Opening the connection with foreign keys=True
works fine if the dialog isn't shown or if it is shown after any other SQLite connection is opened. The code also works fine if the program runs as a 32-bit process. The behaviour is also the same if I use either the single mixed mode x64 SQLite assembly or the MSIL + x64 interop assembly. I'm using v1.0.92.0 so this is not the problem.
So the question is why would showing the FolderBrowserDialog
affect the System.Data.SQLite assembly finding the entry point in its own interop library and why would it only occur in a 64-bit process?
As a work around I can load an in-memory database before doing anything else in the program but I don't like this "solution" as I'm using EF6 and would like to be able to use different providers configured via a config file or even at runtime via user input. Hence all the sqlite specific code is in another assembly.
An older version of
System.Data.SQLite
is being loaded when displaying theFolderBrowserDialog
. If there are any shell / explorer extensions installed on the computer then displaying any of the common dialogs which includes Explorer will cause assemblies from those extensions to be loaded into the application'sAppDomain
.In the case of
System.Data.SQLite
a native library is loaded (SQLite.Interop.dll
) resulting in all loaded versions of the assembly to use that version of the native library. Loading the new version of the assembly first causes the new version of the native library to be loaded. This still results in multiple versions of the assembly being loaded in the AppDomain though and it means that shell extensions will be using a different version than they expect.I tried opening the the
FolderBrowserDialog
in a different AppDomain but it still results in assemblies being loaded into the application's normal AppDomain. I've opened a bug on Microsoft connect regarding this but I'm not too hopeful that it will be fixed.As a workaround I've added this to my app.config:
This results in only the single version of
System.Data.SQLite
being loaded. It does still mean that shell extensions will be using the wrong version and hence could potentially throw exceptions.I had the same issue when I used
GMAP.NET
, which appeared to be opening an SQLite connection using an older version. Then, when I attempted to open a connection with the newer version, the error withSQLite.Interop.dll
occurred.By opening a dummy connection with the newer version before instantiating the
GMAP.NET
object using the older connection, the error went away. The connection doesn't have to do anything, it just has to be opened first.