解决方案 1:
乍一看,在加载托管包装器之前自己加载目标本机 dll 似乎是一个很好的解决方案(通过使用带有绝对路径的 LoadLibrary 调用)
[DllImport("kernel32", SetLastError=true, CharSet = CharSet.Ansi)]
static extern IntPtr LoadLibrary([MarshalAs(UnmanagedType.LPStr)]string lpFileName);
来自docs.microsoft.com:
如果字符串指定了完整路径,则函数只搜索
模块的路径。
我还想谈谈另一种方法,我尝试过成功。
解决方案 2:
我们可以使用 SetDllDirectory 原生 API 为 LoadLibrary 的搜索顺序注入一条新路径。
原生库是使用LoadLibrary函数加载的,要加载的库有一定的directory search order。
请参阅从 LoadLibrary 函数的文档中截取的部分:
可以使用 SetDllDirectory 函数更改搜索路径。
建议使用此解决方案,而不是使用 SetCurrentDirectory 或
对 DLL 的完整路径进行硬编码。
我向一个不存在的模块添加了一个符号互操作调用:
[DllImport("oguzozgul.dll")]
static extern uint InvokeOguzOzgul(IntPtr oguz, uint ozgul);
然后调用这个函数并用ProcMon监控搜索行为
您可以清楚地看到 LoadLibrary 查找本机图像的顺序。 (在我的系统上)
然后,在调用这个不存在的模块之前,我调用了 [SetDllDirectory]:
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool SetDllDirectory(string lpPathName);
// Calling SetDllDirectory:
SetDllDirectory("c:\\temp\\");
然后再次调用该方法。结果如下。
检查进程文件夹后,LoadLibrary 立即检查注入路径。
因此,如果您调用 SetDllDirectory 并将正确的目录路径添加到 LoadLibrary 的搜索顺序中,则应在托管包装器需要时自动从那里加载所需版本的本机 dll。
希望这会有所帮助。