开发者

Loading x86 or x64 assembly

开发者 https://www.devze.com 2023-01-17 23:31 出处:网络
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.

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?


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


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.


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


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.


You could use Environment.Is64BitProcess to identify the process as 64 bit. (I would try to avoid catching exceptions as flow-control wherever possible.)


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...


  1. install appropriate DLL in the GAC (e.g. 64bit version on a 64bit platform)
  2. use assembly binding in your web/app configuration (possibly in machine config)
  3. Fully qualify any partial assembly references in your web/app config.
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号