使用C#中的DllImport一个32位或64位的DLL使用C#中的DllImport一个32位或6

2019-05-12 21:50发布

这里的情况是,我用我的dot.net申请一个基于C的DLL。 有2个DLL文件,一个是32位叫MyDll32.dll,另一个是名为MyDll64.dll 64位版本。

有一个静态变量持有的DLL文件名:字符串DLL_FILE_NAME。

并且在使用方式如下:

[DllImport(DLL_FILE_NAME, CallingConvention=CallingConvention.Cdecl, EntryPoint=Func1")]
private static extern int is_Func1(int var1, int var2);

简单为止。

你可以想像,软件编译打开“任何CPU”。

我也有下面的代码,以确定系统应使用64位文件或32位文件。

#if WIN64
        public const string DLL_FILE_NAME = "MyDll64.dll";
#else
        public const string DLL_FILE_NAME = "MyDll32.dll";        
#endif

现在,你应该看到这个问题.. DLL_FILE_NAME在编译时间定义,而不是在执行时间,以便正确的dll是根据执行上下文不加载。

什么是解决这个问题的正确方法是什么? 我不想要两个可执行文件(一个用于32位,另一个用于64位)? 如何设置DLL_FILE_NAME它在的DllImport语句中使用吗?

Answer 1:

我发现这样做最简单的方法是将两种方法具有不同名称导入,并调用正确的。 该DLL将不会被加载,直到呼叫被制成所以它的罚款:

[DllImport("MyDll32.dll", EntryPoint = "Func1", CallingConvention = CallingConvention.Cdecl)]
private static extern int Func1_32(int var1, int var2);

[DllImport("MyDll64.dll", EntryPoint = "Func1", CallingConvention = CallingConvention.Cdecl)]
private static extern int Func1_64(int var1, int var2);

public static int Func1(int var1, int var2) {
    return IntPtr.Size == 8 /* 64bit */ ? Func1_64(var1, var2) : Func1_32(var1, var2);
}

当然,如果你有很多的进口,这可以成为相当繁琐手工维护。



Answer 2:

下面是要求两个DLL具有相同的名称和被放在不同的文件夹中另一种选择。 例如:

  • win32/MyDll.dll
  • win64/MyDll.dll

关键是要手动加载DLL LoadLibrary的CLR不前。 然后,它会看到一个MyDll.dll已加载并使用它。

这可以很容易地在父类的静态构造函数来完成。

static class MyDll
{
    static MyDll()
    {            
        var myPath = new Uri(typeof(MyDll).Assembly.CodeBase).LocalPath;
        var myFolder = Path.GetDirectoryName(myPath);

        var is64 = IntPtr.Size == 8;
        var subfolder = is64 ? "\\win64\\" : "\\win32\\";

        LoadLibrary(myFolder + subfolder + "MyDll.dll");
    }

    [DllImport("kernel32.dll")]
    private static extern IntPtr LoadLibrary(string dllToLoad);

    [DllImport("MyDll.dll")]
    public static extern int MyFunction(int var1, int var2);
}

编辑2017年2月1日 :使用Assembly.CodeBase使其作品即使阴影复制启用。



Answer 3:

在这种情况下,我应该做这样的(做2个文件夹,x64和x86 +把相应的DLL,具有相同的名称,在这两个文件夹):

using System;
using System.Runtime.InteropServices;
using System.Reflection;
using System.IO;

class Program {
    static void Main(string[] args) {
        var path = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
        path = Path.Combine(path, IntPtr.Size == 8 ? "x64" : "x86");
        bool ok = SetDllDirectory(path);
        if (!ok) throw new System.ComponentModel.Win32Exception();
    }
    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern bool SetDllDirectory(string path);
}


Answer 4:

有一个静态变量持有的DLL文件名

它不是一个静态变量。 这是一个常数,在编译时。 你不能改变一个编译时在运行时不变。

什么是解决这个问题的正确方法是什么?

老实说,我会建议只是针对x86和遗忘的64位版本都在一起,并让在WOW64应用程序运行,除非你的应用程序有一个迫切需要为64位运行。

如果有需要的X64,您可以:

  • 更改DLL文件具有相同的名称,如MyDll.dll ,并在安装/部署的时间,把正确的到位。 (如果操作系统是64位,部署DLL的64位版本,否则x86版本)。

  • 有两个单独的构建完全,一个用于x86,一个用于x64的。



Answer 5:

什么你描述被称为“并排侧组装件”(同一程序集的两个版本,一个32和其他64位)......我想你会发现这些有用的:

  • 使用侧面并排组件加载DLL的64或32倍的版本
  • http://blogs.msdn.com/b/gauravseth/archive/2006/03/07/545104.aspx
  • http://www.thescarms.com/dotnet/Assembly.aspx

在这里你可以找到你的确切方案(.NET DLL环绕C ++ / CLI DLL引用本地DLL)的演练。

建议:

只是打造为x86和用它做......或有2个建立(一个x86和一个64位)......作为上述技术相当复杂...



Answer 6:

一种替代方法可以是

public static class Sample
{
    public Sample()
    {

        string StartupDirEndingWithSlash = System.IO.Path.GetDirectoryName(System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName) + "\\";
        string ResolvedDomainTimeFileName = StartupDirEndingWithSlash + "ABCLib_Resolved.dll";
        if (!File.Exists(ResolvedDomainTimeFileName))
        {
            if (Environment.Is64BitProcess)
            {
                if (File.Exists(StartupDirEndingWithSlash + "ABCLib_64.dll"))
                    File.Copy(StartupDirEndingWithSlash + "ABCLib_64.dll", ResolvedDomainTimeFileName);
            }
            else
            {
                if (File.Exists(StartupDirEndingWithSlash + "ABCLib_32.dll"))
                    File.Copy(StartupDirEndingWithSlash + "ABCLib_32.dll", ResolvedDomainTimeFileName);
            }
        }
    }

    [DllImport("ABCLib__Resolved.dll")]
    private static extern bool SomeFunctionName(ref int FT);
}


Answer 7:

我已经使用vcsjones meantioned的方法之一:

“更改DLL文件具有相同的名称,如将myDll.dll,并在安装/部署时间,落实到位是正确的。”

这种方式需要维护两个构建平台,虽然看到此链接了解详情: https://stackoverflow.com/a/6446638/38368



Answer 8:

我使用的窍门V8.Net是这样的:

  1. 创建所有的定义了不同的体系结构之间切换一个新的C#“代理接口”项目。 在我的情况下,项目被命名为V8.Net-ProxyInterface ; 例:
 public unsafe static class V8NetProxy
    {
    #if x86
            [DllImport("V8_Net_Proxy_x86")]
    #elif x64
            [DllImport("V8_Net_Proxy_x64")]
    #else
            [DllImport("V8_Net_Proxy")] // (dummy - NOT USED!)
    #endif
            public static extern NativeV8EngineProxy* CreateV8EngineProxy(bool enableDebugging, void* debugMessageDispatcher, int debugPort);

这是你将引用该项目。 不引用下两个:

  1. 创建两个项目生成库的x64和x86版本。 这是很容易:只要复制正粘贴复制.csproj在同一个文件夹中的文件和他们改名。 在我的情况下,项目文件更名为V8.Net-ProxyInterface-x64V8.Net-ProxyInterface-x86 ,然后我添加项目到我的解决方案。 在Visual Studio中打开为他们每个人的项目设置,确保Assembly Name在名称中包含任何的x64或x86。 在这一点上,你有3个项目:第一个“占位符”项目,并在2特定架构的。 对于2个新项目:

    a)打开64接口项目设置,转到Build选项卡,选择All PlatformsPlatform顶部,然后输入x64Conditional compilation symbols

    B)打开了x86接口项目设置,转到Build选项卡,选择All PlatformsPlatform顶部,然后输入x86Conditional compilation symbols

  2. 打开Build->Configuration Manager... ,并确保x64被选中作为平台,x64的项目, x86选择为x86项目,对于这两种DebugRelease配置。

  3. 确保2个新的界面项目(用于x64和x86)输出到主机项目的同一位置(见项目设置Build->Output path )。

  4. 最终魔术:在我的引擎静态构造函数我迅速连接到集解析器:

static V8Engine()
{
    AppDomain.CurrentDomain.AssemblyResolve += Resolver;
}

Resolver的方法,我只是加载基于当前进程表示当前平台上的文件(注意:此代码是一个精简版和未测试):

var currentExecPath = Assembly.GetExecutingAssembly().Location;
var platform = Environment.Is64BitProcess ? "x64" : "x86";
var filename = "V8.Net.Proxy.Interface." + platform + ".dll"
return Assembly.LoadFrom(Path.Combine(currentExecPath , fileName));

最后,进入到你的主机项目在解决方案资源管理器中,展开References ,选择在步骤1中创建的第一虚设项目,右键单击它,打开属性,设置Copy Localfalse 。 这可以让你用一个名字来为每一个P /调用功能,同时采用了旋找出哪一个实际加载。

请注意,必要时组装装载机只运行。 它仅是通过在第一次接触到发动机类CLR系统触发(对我来说)自动。 那如何转化为你要看你的主机项目是如何设计的。



文章来源: Using a 32bit or 64bit dll in C# DllImport