简体   繁体   English

加载x86或x64程序集

[英]Loading x86 or x64 assembly

I have two versions of System.Data.SQLite.DLL - for x86 and x64 platform. 我有两个版本的System.Data.SQLite.DLL-用于x86和x64平台。 The x86 version keeps in application folder and x64 version keeps in appFolder\\x64 folder. x86版本保留在应用程序文件夹中,而x64版本保留在appFolder \\ x64文件夹中。 The application compiled as AnyCPU. 该应用程序编译为AnyCPU。 How can i load needed version of SQLite according to windows platform? 如何根据Windows平台加载所需版本的SQLite?

If you are using SQLite from http://system.data.sqlite.org , the System.Data.SQLite.DLL is completely managed. 如果您正在使用来自http://system.data.sqlite.org的 SQLite,则将完全管理System.Data.SQLite.DLL。 There is an underlying native DLL, SQLite.Interop.DLL, that needs to change depending on the process (32- or 64-bit). 有一个基础本机DLL SQLite.Interop.DLL,需要根据进程(32位或64位)进行更改。

I deploy the native libraries in ".\\Native\\X64" for 64-bit and ".\\Native\\X86" for 32-bit. 我将本地库部署在“。\\ Native \\ X64”中(用于64位)和“。\\ Native \\ X86”中(用于32位)。 At runtime P/Invoke SetDllDirectory to set the DLL load directory pointing at the correct path for the process. 在运行时,P / Invoke SetDllDirectory以设置指向该进程正确路径的DLL加载目录。 http://msdn.microsoft.com/en-us/library/ms686203(v=vs.85).aspx http://msdn.microsoft.com/zh-CN/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 ) (请注意,我不熟悉来自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);

Some antivir progs prevent SetDllDirectory() - took me a long time to realize that. 一些抗病毒程序阻止SetDllDirectory()-我花了很长时间才意识到这一点。 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. 用显式路径加载x64 DLL。 It is loaded at that point and the .NET Runtime will use the in-memory DLL instead of searching the disk for it. 届时它将被加载,.NET运行时将使用内存中的DLL,而不是在磁盘上进行搜索。

There is built-in support for this in 1.0.80.0 and later. 1.0.80.0及更高版本对此提供了内置支持。

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. 它从1.0.80.0版本开始可用,并且默认情况下启用。 (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: 但是,要使其在我自己的插件中起作用,我还必须在首次引用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...

See this question: New SQLite mixed assemblies 看到这个问题: 新的SQLite混合程序集

I'm surprised that this works at all. 我很惊讶这一切都奏效。 It should find the x86 version first and fail. 它应该先找到x86版本,然后失败。 A failed assembly bind doesn't produce another attempt through AssemblyResolve. 失败的程序集绑定不会通过AssemblyResolve再次尝试。

Clearly, the CLR cannot actually find the x86 version or this would fail in x64 mode as well. 显然,CLR实际上无法找到x86版本,否则在x64模式下也会失败。 In other words, when you fix the problem, you'll break the 64-bit code. 换句话说,解决问题时,您将破坏64位代码。 Chase the x86 problem first, use Fuslogvw.exe to see which folders are being probed for the assembly. 首先要解决x86问题,请使用Fuslogvw.exe查看正在为程序集探测的文件夹。

A real fix should include moving the x86 assembly into a separate folder as well and adjusting your event handler accordingly. 真正的解决方法应该包括将x86程序集也移到单独的文件夹中,并相应地调整事件处理程序。 You can test IntPtr.Size to find out if you're running in 64-bit mode (Size == 8). 您可以测试IntPtr.Size来确定您是否在64位模式下运行(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. Assembly.GetEntryAssembly()。Location获取您EXE的路径。

You could use Environment.Is64BitProcess to identify the process as 64 bit. 您可以使用Environment.Is64BitProcess将进程标识为64位。 (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? 您难道不只是将SQLite的源代码用作解决方案中的单独项目,而不是使用预编译的程序集吗? Using AnyCPU the system itself will take care of everything and you don't have to do it in code... 使用AnyCPU,系统本身将处理所有事情,而您不必在代码中完成它...

  1. install appropriate DLL in the GAC (eg 64bit version on a 64bit platform) 在GAC中安装适当的DLL(例如,在64位平台上为64位版本)
  2. use assembly binding in your web/app configuration (possibly in machine config) 在Web /应用程序配置中使用程序集绑定(可能在计算机配置中)
  3. Fully qualify any partial assembly references in your web/app config. 完全限定您的Web /应用程序配置中的任何部分程序集引用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM