当所需 DLL 的名称可以更改时,如何 select 在 运行 时 DllImport 的路径?

How to select the path for DllImport at run-time when the name of the required DLL can change?

我今天问过这个问题,但是它被错误地关闭了,我没有办法重新打开它。因此,我不得不再问一次。

我有一个 class,其中有一长串如下定义:

[DllImport(NativeLibraryName, EntryPoint = "FunctionName", CallingConvention = CallingConvention.Cdecl)]
public static extern void FunctionName();

参数“NativeLibraryName”由编译器开关设置。但是,我想在 运行 时间设置此参数。我的问题是我需要考虑两种不同的 DLL:一种用于 32 位系统,一种用于 64 位系统,它们的名称不同。我想要实现的是确定应用程序是 运行 64 位还是 32 位并使用正确的 DLL。我需要加载正确的 DLL,否则我 运行 进入 BadImageFormatExceptions。

切换到代表

我可以使用反射生成一个文件,该文件的作用与使用委托 like this 给出的文件相同。在这里,我可以在 运行 时提供正确 DLL 的路径。

重命名 DLL

我也可以重命名这两个DLL,让它们重名,但放在不同的目录中。然后我可以 select 我想从中加载 DLL 的文件夹。

这两个选项都可以正常工作,但我正在处理的项目是现有项目的分支,我想尽可能少地更改,以便我可以轻松地将原始项目的更新合并到我的项目中。

我很高兴你有任何想法。

This thread 被错误地建议为我的问题的解决方案,之后原始线程被关闭。这个线程讨论了一个类似的问题,但它没有提供适用于我的问题的解决方案。事实上,实际上提出了我自己想出的解决方案之一,但我正在寻找更好的方法。

一个简单的方法是确保 DLL 具有相同的文件名(例如 MyNativeLibrary.dll)并将它们存储在单独的子文件夹中,例如:

  • x86\MyNativeLibrary.dll 对于 32 位 DLL
  • x64\MyNativeLibrary.dll 64 位 DLL

声明 P/Invoke 方法时,您使用库的名称而不指定硬编码路径,例如:

public static class MyUtilityClass
{
    [DllImport("MyNativeLibrary.dll")]
    public static extern int DoSomething(int x, int y);
}

最后,如果您的应用程序使用NativeLibrary.Load(string),则在开始时传入您要加载的 DLL 的完整路径。这必须在 尝试调用您的 DLL 的任何函数之前完成。

// Pseudo-code. You might need to adapt to find the path where your DLLs are located

// Get the folder path where the current `App.exe` is located
var startupPath = Path.GetDirectoryName(Process.GetCurrentProcess().MainModule?.FileName);

// Assume the DLL is in a sub-folder of the folder where `App.exe` is located
var myLibraryFullPath = Environment.Is64BitProcess
    ? Path.Combine(startupPath, @"x64\MyNativeLibrary.dll")
    : Path.Combine(startupPath, @"x86\MyNativeLibrary.dll");

// Load the appropriate DLL into the current process
NativeLibrary.Load(myLibraryFullPath);

一旦将非托管 DLL 加载到进程中,任何用 [DllImport("MyNativeLibrary.dll")] 修饰的未来 P/Invoke 将绑定到已加载的 DLL,这就是它起作用的原因。