加载x86或x64程序集

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

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

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

(请注意,我不熟悉http://sqlite.phxsoftware.com上遗留的System.Data.SQLite.DLL版本的体系结构)

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

一些antivir progs阻止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); 

使用显式路径加载x64 DLL。 它在那时加载,.NET Runtime将使用内存中的DLL而不是在磁盘上搜索它。

1.0.80.0及更高版本内置了对此的支持。

如果开发和客户机器可能具有不同的处理器体系结构,则可能需要多个二进制包。 对于这种情况,强烈建议使用本机库预加载function 。 它从版本1.0.80.0开始提供,默认情况下启用。 (来自下载页面)

但是,为了让它在我自己的插件中工作,我还必须在第一次引用SQLite之前添加它:

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

看到这个问题: 新的SQLite混合程序集

我很惊讶这一点都有效。 它应该首先找到x86版本并失败。 失败的程序集绑定不会通过AssemblyResolve产生另一次尝试。

显然,CLR实际上找不到x86版本,否则在x64模式下也会失败。 换句话说,当您解决问题时,您将破坏64位代码。 首先追逐x86问题,使用Fuslogvw.exe查看正在为程序集探测的文件夹。

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

您可以使用Environment.Is64BitProcess将进程标识为64位。 (我会尽量避免将exception作为流量控制来捕获。)

难道你不能只使用SQLite的源代码作为解决方案中的单独项目而不是预编译的程序集吗? 使用AnyCPU,系统本身将处理所有事情,您不必在代码中执行此操作…

  1. 在GAC中安装适当的DLL(例如64位平台上的64位版本)
  2. 在您的web / app配置中使用程序集绑定(可能在机器配置中)
  3. 完全限定Web / app配置中的任何部分程序集引用。