我有两个版本的System.Data.SQLite.DLL - 适用于x86和x64平台。 x86版本保留在应用程序文件夹中,x64版本保留在appFolder \ x64文件夹中。 该应用程序编译为AnyCPU。 如何根据Windows平台加载所需的SQLite版本?
答案 0 :(得分:17)
如果您使用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);
答案 1 :(得分:11)
一些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,而不是在磁盘上搜索它。
答案 2 :(得分: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
答案 3 :(得分:3)
我很惊讶这一点起作用了。它应该首先找到x86版本并失败。失败的程序集绑定不会通过AssemblyResolve产生另一次尝试。
显然,CLR实际上找不到x86版本,否则在x64模式下也会失败。换句话说,当您解决问题时,您将破坏64位代码。首先追逐x86问题,使用Fuslogvw.exe查看正在为程序集探测的文件夹。
真正的修复方法应该包括将x86程序集移动到单独的文件夹中并相应地调整事件处理程序。您可以测试IntPtr.Size以查明您是否以64位模式运行(大小== 8)。另外一定要生成一个完整的路径名,当应用程序的工作目录没有设置在你希望的位置时,使用像现在这样的相对路径会导致失败。 Assembly.GetEntryAssembly()。Location为您提供EXE的路径。
答案 4 :(得分:1)
您可以使用Environment.Is64BitProcess将进程标识为64位。 (我会尽量避免将异常作为流量控制来捕获。)
答案 5 :(得分:0)
难道您不能仅将SQLite源用作解决方案中的单独项目而不是预编译程序集吗?使用AnyCPU,系统本身将处理所有事情,您不必在代码中执行此操作...
答案 6 :(得分:0)