【问题标题】:Loading .net wrapper fails to load native dependency加载 .net 包装器无法加载本机依赖项
【发布时间】:2020-04-17 22:41:38
【问题描述】:

情况:.net 包装类的多个版本,都具有相同的名称和相同的签名。我们希望在 wcf 服务方法中动态加载 1 个包装器。我计划使用每个包装器 + 依赖 dll 设置文件夹。我们将根据用户选择的版本使用 switch 或 if 语句来运行。

我有带有路径的 Assembly.LoadFrom 并且可以创建包装类的实例。但是调用包装器中的方法失败并显示“无法加载或找到 CTV.dll”。

如果我将机器或用户环境路径更改为指向 CTV.dll,它将执行该方法。但这是全局的,只会指向一个版本文件夹中的特定 CTV.dll。我试过很多次了

Environment.SetEnvironmentVariable("Path", [文件夹中ctv.dll的路径], EnvironmentVariableTarget.Process);

但是is没有效果,出现同样的错误。

有什么我想念的吗?看来这个问题应该有答案了。

还有其他方法来处理这个用例吗?

【问题讨论】:

  • 为他人澄清。我需要加载的依赖 dll 是本机 dll,不是托管的。

标签: c# wrapper .net-assembly


【解决方案1】:

解决方案 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。

希望这会有所帮助。

【讨论】:

  • Oguz,非常感谢您花时间向我解释这一点。我实现了方法 2,效果很好。
猜你喜欢
  • 1970-01-01
  • 2022-07-11
  • 2019-03-07
  • 2022-01-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多