2010-09-24 67 views
12

我有两个版本的System.Data.SQLite.DLL - 适用于x86和x64平台。 x86版本保留在应用程序文件夹中,x64版本保存在appFolder \ x64文件夹中。 编译为AnyCPU的应用程序。 如何根据Windows平台加载所需的SQLite版本?加载x86或x64程序集

回答

17

如果您正在使用SQLite从http://system.data.sqlite.org,该System.Data.SQLite.DLL完全管理。有一个底层原生DLL,SQLite.Interop.DLL,需要根据进程(32位或64位)进行更改。

我部署在“\本地\ X64" 本地库为64位和” \本地\ X86" 32位。在运行时P/Invoke SetDllDirectory设置DLL加载目录指向进程的正确路径。 http://msdn.microsoft.com/en-us/library/ms686203(v=vs.85).aspx

(请注意,我不熟悉的传统System.Data.SQLite.DLL版本从http://sqlite.phxsoftware.com架构)

private static class NativeMethods 
{ 
    [DllImport("kernel32.dll", CallingConvention = CallingConvention.Cdecl)] 
    internal static extern bool SetDllDirectory(string pathName); 
} 

... 

    // Underlying SQLite libraries are native. 
    // Manually set the DLL load path depending on the process. 
    var path = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "Native"); 
    if(IntPtr.Size == 8) // or: if(Environment.Is64BitProcess) // .NET 4.0 
    { 
     path = Path.Combine(path, "X64"); 
    } 
    else 
    { 
     // X32 
     path = Path.Combine(path, "X86"); 
    } 
    NativeMethods.SetDllDirectory(path); 
+3

我已经解决了这个问题。谢谢。我用“IntPtr.Size == 8”。我使用AppDomain.CurrentDomain.AssemblyResolve代替SetDllDirectory。 – Rover 2011-05-20 10:18:27

1

您可以使用Environment.Is64BitProcess来将进程标识为64位。 (我会尽量避免捕捉异常的流量控制尽可能。)

+0

这是个好主意,但它不能解决我的问题。 – Rover 2010-09-24 13:28:09

+0

@Rover:怎么样?你一定有64位.NET安装? – 2010-09-24 13:42:30

+0

我使用没有这个变量的.NET 3.5。我想我可以检查平台的版本,但它只是避免捕捉一些例外,但需要汇编不加载。 – Rover 2010-09-24 13:55:41

0

你不能只使用SQLite的源作为一个单独的项目在您的解决方案,而不是一个预编译组件?使用AnyCPU系统本身会照顾一切,你不必做的代码...

+0

这是我在x86和x64上使用的dll之一。我没有所有使用dll的源代码。 – Rover 2010-09-24 13:31:25

+0

这并不能解决任何问题,因为开发机器的架构并不总是与部署机器相同。任何CPU只适用于.NET程序集,而不适用于本机DLL(在引擎盖下使用SQLITE) – BigBoss 2013-10-05 10:00:21

3

我很惊讶,这在所有工作。它应该首先找到x86版本并且失败。一个失败的程序集绑定不会通过AssemblyResolve产生另一个尝试。

显然,CLR实际上找不到x86版本,或者在x64模式下也会失败。换句话说,当你解决这个问题时,你会破坏64位代码。首先追踪x86问题,使用Fuslogvw.exe查看该程序集正在探测哪些文件夹。

一个真正的修复应该包括将x86程序集移动到一个单独的文件夹中,并相应地调整您的事件处理程序。您可以测试IntPtr.Size以确定您是否以64位模式运行(大小== 8)。此外,请确保生成完整的路径名称,使用现在使用的相对路径可能会导致应用程序的工作目录未设置在希望的位置。 Assembly.GetEntryAssembly()。位置为您提供EXE的路径。

+0

我删除了代码以避免混淆,只留下问题。 – Rover 2010-09-24 14:16:06

+0

嗯,我不认为这改变了我的答案。最后一段告诉你如何做对。 – 2010-09-24 14:17:35

+0

好吧,我查了个平台,找到了需要的程序集。我应该如何将程序集加载到AppDomain中? – Rover 2010-09-24 14:32:58

0
  1. 在GAC中安装相应的DLL(例如,64位版本在一个64位平台上)
  2. 在你的web/app配置中使用程序集绑定(可能在机器配置中)
  3. 完全限定你的web/app配置中的任何部分程序集引用。
5

还有就是内置支持这1.0.80.0及更高版本。

如果开发和客户机器可能有不同的处理器体系结构,可能需要多个二进制包。对于这种情况,强烈建议使用本机库预加载功能。它从版本1.0.80.0开始可用,并且默认启用。(from download page)

但是,要获得它在我自己的工作插件我也有参考SQLite的首次之前,补充一点:

// Make SQLite work... (loading dll from e.g. x64/SQLite.Interop.dll) 
System.Environment.SetEnvironmentVariable("PreLoadSQLite_BaseDirectory", System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location)); 

Sql.Data.SQLite... 

看到这个问题:New SQLite mixed assemblies

11

一些反病毒程序阻止SetDllDirectory() - 花了很长时间才意识到这一点。 我们使用

System.Reflection.Assembly myass = System.Reflection.Assembly.GetExecutingAssembly(); 
FileInfo fi = new FileInfo(myass.Location); 
System.IntPtr moduleHandle = LoadLibraryEx(fi.Directory.FullName + "\\x64\\SQLite.Interop.DLL", IntPtr.Zero, 0); 

加载使用显式路径64 DLL。它在那个时候加载,并且.NET运行时将使用内存中的DLL,而不是在其中搜索磁盘。

+5

Upvote for myass' :) – 2015-06-30 11:47:50

+0

在我的情况下没有工作。即使我已经使用调试器进行了验证,但是本机库可以正确加载。 SQLite仍然抛出关于本地DLL丢失的异常。 – BartoszKP 2016-12-13 15:22:20