Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
571 views
in Technique[技术] by (71.8m points)

c# - EntryPointNotFoundException in SQLite after displaying FolderBrowserDialog

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.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

An older version of System.Data.SQLite is being loaded when displaying the FolderBrowserDialog. 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's AppDomain.

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:

<runtime>
  <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
    <dependentAssembly>
      <assemblyIdentity name="System.Data.SQLite"
                        version="1.0.92.0"
                        publicKeyToken="DB937BC2D44FF139"
                        language="neutral"
                        processorArchitecture="msil" />
      <bindingRedirect oldVersion="0.0.0.0-1.0.91.65535" newVersion="1.0.92.0" />
    </dependentAssembly>
  </assemblyBinding>
</runtime>

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...