【问题标题】:How to set search path for dllimport in mono?如何在单声道中设置 dllimport 的搜索路径?
【发布时间】:2017-04-28 12:06:20
【问题描述】:

我正在开发一个 Unity 应用程序,它需要从安装应用程序的外部动态加载本机库,由于某种原因,我无法在编译之前将绝对路径设置为 DllImport(例如读取 . txt 在运行时并加载它),我不想使用平台特定的 API,例如 Windows 上的 LoadLibrary() 或 Linux 上的 dlopen,因为它不方便。而且我已经挣扎了好几天了。

我知道搜索路径可以通过SetDllDirectory()在Windows上从this post进行调整,并且在.NET Framework应用程序上测试时效果很好。 但是,它在基于 mono 2.0 的 Unity 中不起作用,它只是在运行时抛出 DllNotFoundException,但是当我在 DllImport 中使用绝对路径或将 dll 复制到我的 Unity 项目中时它工作正常(我确定代码相同)

我尝试的下一个方法是环境变量,它不适用于 .NET 和 Mono,this post 解释说 CLR 在进程执行期间从不刷新环境。

我尝试的第三种方法是使用特定于平台的API加载本机库,例如Windows上的LoadLibrary()和Linux上的dlopen(),然后Dllimport可能会发现已经加载了同名的库,然后它将使用加载库来查找函数指针,就像this post 所做的那样。我得到了同样的结果。该问题的最佳答案是我们可以编写一个包装类,它使用特定于平台的 API 来显式加载库并获取函数指针,而不是专注于 Dllimport 的方法,但这不是我想要的。

如果我的猜测是正确的,根据mono's documentDllImportAttribute 在运行时内部调用LoadLibrarydlopen 以将库加载到内存空间中。所以它遵循特定操作系统平台的搜索规则,例如windows:

  1. 加载应用程序的目录。
  2. 当前目录
  3. 系统目录。使用GetSystemDirectory()函数获取该目录的路径。
  4. 16 位系统目录。
  5. Windows 目录。使用GetWindowsDirectory()函数获取 此目录的路径。
  6. PATH 环境变量中列出的目录。

和 Linux:

  1. 用户LD_LIBRARY_PATH 中以冒号分隔的目录列表 环境变量。这是一种常用的方式来让原生 由 CLI 程序找到的共享库。
  2. /etc/ld.so.cache 中缓存的库列表。 /etc/ld.so.cache 通过编辑/etc/ld.so.conf 并运行ldconfig(8) 创建。 编辑/etc/ld.so.conf 是搜索附加信息的首选方式 目录,而不是使用LD_LIBRARY_PATH,因为这样更 安全(木马库更难进入 /etc/ld.so.cache 而不是将其插入LD_LIBRARY_PATH)。
  3. /lib,然后是/usr/lib

顺便说一句,我也尝试在运行时设置LD_LIBRARY_PATH,但它不起作用,因为LD_LIBRARY_PATH只会在进程启动时被解析一次,这类似于Windows上的PATH环境变量。

所以我的问题是:

  1. 为什么相同的代码在 .NET Framework 和 Mono 上执行不同? Mono 是否只是忽略了SetDllDirectory() 在 Windows 上的影响? DllImportAttribute 在 Mono 中实际上做了什么?
  2. 有没有办法在运行时调整 Unity/Mono 应用程序的搜索路径,只使用 DllImport 而不是平台特定的 API,例如 LoadLibrary()dlopen()

【问题讨论】:

    标签: c# .net mono pinvoke dllimport


    【解决方案1】:

    不幸的是,答案是这种行为在 Linux 上的 Mono 和 Windows 上的 .Net 之间是不同的,所以你只需要处理这个问题。

    如果您知道每个 DLL 的位置(例如,您可以将其放入配置文件),最好的选择是使用 LoadLibrarydlopen 自己显式加载每个 DLL。这必须在第一次调用DllImport 函数之前完成。 DllImport 然后不需要指定路径。

    这样您就可以确切地知道您正在获取哪个 DLL,并且可以以任何正确的顺序加载它们(如果这是一个问题)。

    如果出于某种原因您真的不想这样做,我建议您创建一个类似MySetDllDirectory 的函数,在 Windows 上调用 SetDllDirectory 而在 Linux 上设置 LD_LIBRARY_PATH。通过这种方式,可以将更改隔离到单个模块。

    【讨论】:

      猜你喜欢
      • 2011-02-21
      • 1970-01-01
      • 2016-12-05
      • 1970-01-01
      • 2022-12-10
      • 2014-03-22
      • 1970-01-01
      • 2011-09-13
      • 1970-01-01
      相关资源
      最近更新 更多