windows 导入基于 64 位或 32 位操作系统的外部 dll

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2593916/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-15 14:14:31  来源:igfitidea点击:

Import external dll based on 64bit or 32bit OS

c#.netwindowswinforms

提问by Mike_G

I have a dll that comes in both 32bit and 64bit version. My .NET WinForm is configured for "Any CPU" and my boss will not let us have separate installs for the different OS versions. So I am wondering: if I package both dlls in the install, then is there a way to have the WinForm determine if its 64bit/32bit and load the proper dll.

我有一个 32 位和 64 位版本的 dll。我的 .NET WinForm 配置为“任何 CPU”,我的老板不会让我们为不同的操作系统版本单独安装。所以我想知道:如果我在安装中打包了两个 dll,那么有没有办法让 WinForm 确定它的 64 位/32 位并加载正确的 dll。

I found this articlefor determining version. But i am not sure how to inject the proper way to define the DLLImport attribute on the methods i wish to use. Any ideas?

我找到了这篇文章来确定版本。但我不确定如何注入正确的方法来定义我希望使用的方法的 DLLImport 属性。有任何想法吗?

采纳答案by Kieron

Can you import them both and make the decision about which one to call via .NET instead?

您能否同时导入它们并决定通过 .NET 调用哪一个?

For example:

例如:

[DllImport("32bit.dll", CharSet = CharSet.Unicode, EntryPoint="CallMe")]
public static extern int CallMe32 (IntPtr hWnd, String text, String caption, uint type);

[DllImport("64bit.dll", CharSet = CharSet.Unicode, EntryPoint="CallMe")]
public static extern int CallMe64 (IntPtr hWnd, String text, String caption, uint type);

回答by Hans Passant

You could take advantage of the SetDllDirectory API function, it alters the search path for unmanaged assemblies. Store your 32-bit DLLs in the x86 subdirectory of the app install directory, the 64-bit DLLs in the x64 subdirectory.

您可以利用 SetDllDirectory API 函数,它会更改非托管程序集的搜索路径。将 32 位 DLL 存储在应用安装目录的 x86 子目录中,将 64 位 DLL 存储在 x64 子目录中。

Run this code at app startup before you do any P/Invoke:

在执行任何 P/Invoke 之前,在应用程序启动时运行此代码:

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

    public static void SetUnmanagedDllDirectory() {
        string path = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
        path = Path.Combine(path, IntPtr.Size == 8 ? "x64 " : "x86");
        if (!SetDllDirectory(path)) throw new System.ComponentModel.Win32Exception();
    }

    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern bool SetDllDirectory(string path);

回答by SLaks

You should make two different private externmethods, and make an internal method that checks IntPtr.Sizeand calls the correct version.

您应该创建两个不同的私有extern方法,并创建一个内部方法来检查IntPtr.Size和调用正确的版本。

回答by Reed Copsey

My solution is to create a single abstract class, with a concrete version which loads and wraps my 32bit DLL, and a separate implementation that loads and wraps the 64bit DLL. A single factory method in the base class can be used to instantiate the appropriate implementation based on the IntPtr.Size.

我的解决方案是创建一个抽象类,用一个具体版本来加载和包装我的 32 位 DLL,以及一个单独的实现来加载和包装 64 位 DLL。基类中的单个工厂方法可用于实例化基于IntPtr.Size.

The nice thing about this approach is that the rest of your code is completely isolated from the platform - it just constructs an object using your base class factory method, and works with it. It is also very easy to call into multiple methods within the DLLs in question, in a uniform manner, and all of your "native" code can easily be pushed into a private implementation.

这种方法的好处是您的其余代码与平台完全隔离——它只是使用您的基类工厂方法构造一个对象,并使用它。以统一的方式调用相关 DLL 中的多个方法也非常容易,并且您的所有“本机”代码都可以轻松推送到私有实现中。

回答by Andras Vass

...or you can use Marshal.GetDelegateForFunctionPointer()to do dynamic P/Invoke.
...or call LoadLibrary()with a fully qualified pathbefore the CLR tries to load it for you.

...或者你可以Marshal.GetDelegateForFunctionPointer()用来做动态 P/Invoke
...或者在 CLR 尝试为您加载之前LoadLibrary()使用完全限定的路径调用。