EntryPointNotFoundException dans System.Data.SQLite après l’affichage de FolderBrowserDialog

Lors de l’utilisation d’un programme 64 bits, System.Data.SQLite lève l’exception suivante EntryPointNotFoundException:

Impossible de trouver un point d’entrée nommé ‘sqlite3_changes_interop’ dans la DLL ‘SQLite.Interop.dll’.

Étrangement, cela ne se produit que si Foreign Keys=True est spécifié dans la chaîne de connexion et, ce qui est encore plus important, uniquement après avoir affiché un FolderBrowserDialog . Je cherchais un dossier pour afficher les bases de données à charger.

Le code suivant affiche le problème:

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

Ouverture de la connexion avec foreign keys=True fonctionne correctement si la boîte de dialog n’est pas affichée ou si elle apparaît après l’ouverture d’une autre connexion SQLite. Le code fonctionne également correctement si le programme est exécuté en tant que processus 32 bits. Le comportement est également identique si j’utilise l’assembly SQLite x64 unique en mode mixte ou l’assembly d’interopérabilité MSIL + x64. J’utilise v1.0.92.0, alors ce n’est pas le problème.

La question est donc de savoir pourquoi l’affichage de FolderBrowserDialog aurait une FolderBrowserDialog sur l’assemblage System.Data.SQLite lors de la recherche du point d’entrée dans sa propre bibliothèque d’interopérabilité et pourquoi cela ne se produirait-il que dans un processus 64 bits?

Pour contourner le problème, je peux charger une firebase database en mémoire avant de faire quoi que ce soit dans le programme, mais je n’aime pas cette “solution”, car j’utilise EF6 et j’aimerais pouvoir utiliser différents fournisseurs configurés via un fichier de configuration. ou même au moment de l’exécution via une entrée utilisateur. Par conséquent, tout le code spécifique à SQLite se trouve dans un autre assemblage.

Une ancienne version de System.Data.SQLite est en cours de chargement lors de l’affichage de FolderBrowserDialog . Si des extensions shell / explorateur sont installées sur l’ordinateur, le fait d’afficher l’une des boîtes de dialog communes, y compris Explorer, entraînera le chargement des assemblys de ces extensions dans AppDomain l’ AppDomain .

Dans le cas de System.Data.SQLite une bibliothèque native est chargée ( SQLite.Interop.dll ), de sorte que toutes les versions chargées de l’assembly utilisent cette version de la bibliothèque native. Le chargement initial de la nouvelle version de l’assembly entraîne le chargement de la nouvelle version de la bibliothèque native. Cela entraîne néanmoins le chargement de plusieurs versions de l’assembly dans AppDomain, ce qui signifie que les extensions de shell utiliseront une version différente de celle attendue.

J’ai essayé d’ouvrir le FolderBrowserDialog dans un autre FolderBrowserDialog , mais les assemblys sont toujours chargés dans l’appDomain normal de l’application. J’ai ouvert un bogue sur Microsoft Connect à ce sujet, mais je ne souhaite pas trop qu’il soit corrigé.

En guise de solution de contournement, j’ai ajouté ceci à mon app.config:

         

Ainsi, seule la version unique de System.Data.SQLite est chargée. Cela signifie toujours que les extensions de shell utiliseront la mauvaise version et qu’elles pourraient donc générer des exceptions.

J’ai eu le même problème lorsque j’ai utilisé GMAP.NET , qui semblait ouvrir une connexion SQLite avec une version plus ancienne. Ensuite, lorsque j’ai tenté d’ouvrir une connexion avec la version la plus récente, l’erreur avec SQLite.Interop.dll s’est produite.

En ouvrant une connexion fictive avec la version la plus récente avant d’instancier l’object GMAP.NET à l’aide de la connexion plus ancienne, l’erreur a disparu. La connexion n’a rien à faire, il faut juste qu’elle soit ouverte en premier.

 using (SQLiteConnection con = new SQLiteConnection("Data Source=" + dat + ";Version=3;")) { con.Open(); }