I have two versions of System.Data.SQLite.DLL - for x86 and x64 platform. The x86 version keeps in application folder and x64 version keeps in appFolder\x64 folder. The application compiled as AnyCPU. How can i load needed version of SQLite according to windows platform?
问题:
回答1:
If you are using SQLite from http://system.data.sqlite.org, the System.Data.SQLite.DLL is completely managed. There is an underlying native DLL, SQLite.Interop.DLL, that needs to change depending on the process (32- or 64-bit).
I deploy the native libraries in ".\Native\X64" for 64-bit and ".\Native\X86" for 32-bit. At runtime P/Invoke SetDllDirectory to set the DLL load directory pointing at the correct path for the process. http://msdn.microsoft.com/en-us/library/ms686203(v=vs.85).aspx
(Note that I'm not familiar with the architecture of the legacy System.Data.SQLite.DLL version from 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);
回答2:
Some antivir progs prevent SetDllDirectory() - took me a long time to realize that. We are using
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);
to load the x64 DLL with explicit path. It is loaded at that point and the .NET Runtime will use the in-memory DLL instead of searching the disk for it.
回答3:
There is built-in support for this in 1.0.80.0 and later.
If the development and customer machines may have different processor architectures, more than one binary package may be required. For this situation, using the native library pre-loading feature is highly recommended. It is available as of version 1.0.80.0 and enabled by default. (from download page)
However, to get it to work in my own plug-in I also had to add this before referencing SQLite for the first time:
// 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...
See this question: New SQLite mixed assemblies
回答4:
I'm surprised that this works at all. It should find the x86 version first and fail. A failed assembly bind doesn't produce another attempt through AssemblyResolve.
Clearly, the CLR cannot actually find the x86 version or this would fail in x64 mode as well. In other words, when you fix the problem, you'll break the 64-bit code. Chase the x86 problem first, use Fuslogvw.exe to see which folders are being probed for the assembly.
A real fix should include moving the x86 assembly into a separate folder as well and adjusting your event handler accordingly. You can test IntPtr.Size to find out if you're running in 64-bit mode (Size == 8). Also be sure to generate a full path name, using the relative path like you do now can cause failure when the app's working directory isn't set where you hope it is. Assembly.GetEntryAssembly().Location gets you the path of the EXE.
回答5:
You could use Environment.Is64BitProcess to identify the process as 64 bit. (I would try to avoid catching exceptions as flow-control wherever possible.)
回答6:
Couldn't you just use the source of SQLite as a separate project in your solution instead of a precompiled assembly? Using AnyCPU the system itself will take care of everything and you don't have to do it in code...
回答7:
- install appropriate DLL in the GAC (e.g. 64bit version on a 64bit platform)
- use assembly binding in your web/app configuration (possibly in machine config)
- Fully qualify any partial assembly references in your web/app config.