c# - 显示 FolderBrowserDialog 后 SQLite 中的 EntryPointNotFoundException

标签 c# .net sqlite 64-bit system.data.sqlite

当使用 64 位程序时,System.Data.SQLite 抛出以下 EntryPointNotFoundException:

Unable to find an entry point named 'sqlite3_changes_interop' in DLL 'SQLite.Interop.dll'.

奇怪的是,只有在连接字符串中指定了 Foreign Keys=True 时才会发生,更重要的是,只有在我显示 FolderBrowserDialog 之后才会发生。我正在浏览一个文件夹来显示要加载的数据库。

下面的代码显示了问题:

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

如果对话框未显示或在任何其他 SQLite 连接打开后显示,则使用 foreign keys=True 打开连接工作正常。如果程序作为 32 位进程运行,代码也能正常工作。如果我使用单一混合模式 x64 SQLite 程序集或 MSIL + x64 互操作程序集,行为也相同。我正在使用 v1.0.92.0 所以 this不是问题。

所以问题是为什么显示 FolderBrowserDialog 会影响 System.Data.SQLite 程序集在它自己的互操作库中找到入口点,为什么它只发生在 64 位进程中?

作为解决方法,我可以在程序中执行任何其他操作之前加载内存中的数据库,但我不喜欢这种“解决方案”,因为我使用的是 EF6,并且希望能够使用通过配置文件,甚至在运行时通过用户输入。因此,所有 sqlite 特定代码都在另一个程序集中。

最佳答案

显示 FolderBrowserDialog 时正在加载旧版本的 System.Data.SQLite。如果计算机上安装了任何 shell/资源管理器扩展,则显示任何包含资源管理器的常见对话框都会导致这些扩展中的程序集加载到应用程序的 AppDomain 中。

System.Data.SQLite 的情况下,加载 native 库 (SQLite.Interop.dll) 导致程序集的所有加载版本都使用该版本 native 库。加载新版本的程序集首先导致加载新版本的 native 库。这仍然会导致多个版本的程序集被加载到 AppDomain 中,这意味着 shell 扩展将使用与他们预期不同的版本。

我尝试在不同的 AppDomain 中打开 FolderBrowserDialog,但它仍然导致程序集被加载到应用程序的正常 AppDomain 中。我在 Microsoft connect 上打开了一个错误关于这个,但我不太希望它会被修复。

作为解决方法,我已将其添加到我的 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>

这导致仅加载单个版本的 System.Data.SQLite。这仍然意味着 shell 扩展将使用错误的版本,因此可能会抛出异常。

关于c# - 显示 FolderBrowserDialog 后 SQLite 中的 EntryPointNotFoundException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23555146/

相关文章:

c# - Rhino Mocks - 使用 Arg.Matches

c# - C# 最小化所有打开的窗口

linux - EOT 字符坐在终端提示上是一个问题吗?

c# - WCF 和 SOAP header - 如何确保默认 header 元素未在请求中签名?

c# - 在 Entity Framework 中使用 linq 提供多个 List<int> 类型标准

java - 无法打开数据库,因为数据库不存在

c# Entity Framework sqlite (spatialite) 空间日期

c# - IEnumerable - 移动到下一个

c# - 在 C# 中,当一次使用在基本构造函数调用中时,如何解决多重枚举警告?

c# - 找到最接近的字符串匹配