【问题标题】:EntryPointNotFoundException in SQLite after displaying FolderBrowserDialog显示 FolderBrowserDialog 后 SQLite 中的 EntryPointNotFoundException
【发布时间】:2014-06-26 15:14:12
【问题描述】:

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

无法在 DLL“SQLite.Interop.dll”中找到名为“sqlite3_changes_interop”的入口点。

奇怪的是,只有在连接字符串中指定了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 特定代码都在另一个程序集中。

【问题讨论】:

  • 在 64 位系统上加载 FolderBrowserDialog 将初始化 64 位编组,从而为 32 位本机代码带来问题。在这种情况下,对本机 DLL 使用 64 位 SQlite 构建。
  • @EugenRieck SQLite.Interop.dll 和混合模式 System.Data.SQLite.dll 是 64 位版本。使用溢出(MSIL + 互操作)或单一混合模式程序集对行为没有影响。
  • 我说的不是 .NET 程序集,而是这些调用的本机 DLL。
  • @EugenRieck 本机 dll 包含在混合模式程序集中并且是 64 位的。
  • 你确定吗?那么它怎么能作为 32 位进程运行呢?如果您的意思是托管和 32 位和 64 位本机混合模式,我一直看到这种方法失败。

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


【解决方案1】:

显示FolderBrowserDialog 时正在加载旧版本的System.Data.SQLite。如果计算机上安装了任何 shell / explorer 扩展,那么显示任何包含 Explorer 的常见对话框都会导致来自这些扩展的程序集被加载到应用程序的 AppDomain

System.Data.SQLite 的情况下,加载本机库 (SQLite.Interop.dll) 导致所有加载的程序集版本都使用该版本的本机库。加载新版本的程序集首先会导致加载新版本的本机库。这仍然会导致在 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 扩展将使用错误的版本,因此可能会引发异常。

【讨论】:

    【解决方案2】:

    我在使用GMAP.NET 时遇到了同样的问题,它似乎正在使用旧版本打开 SQLite 连接。然后,当我尝试打开与较新版本的连接时,出现了SQLite.Interop.dll 的错误。

    通过在使用旧连接实例化GMAP.NET 对象之前打开与新版本的虚拟连接,错误消失了。连接不需要做任何事情,只需先打开它。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-02-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多