如何设置单声道dllimport的搜索路径?
我正在开发一个Unity应用程序,它需要从安装该应用程序的外部动态加载本机库,出于某种原因,我无法在编译之前设置绝对路径到DllImport
(例如在运行时读取.txt中的库路径并加载它),我不想使用特定于平台的API,例如Windows上的LoadLibrary()
或Linux上的dlopen
,因为这很不方便。 我一直在挣扎好几天。
我知道搜索路径可以通过Windows的SetDllDirectory()
从这篇文章进行调整,并且在.NET Framework应用程序上进行测试时,它的效果很好。 然而,它不适用于基于mono 2.0的Unity,它只是在运行时抛出DllNotFoundException
,但在DllImport
使用绝对路径或将dll复制到我的Unity项目时它工作正常(我确信代码是相同)
我尝试的下一个方法是环境变量,它不能在.NET和Mono上工作,这篇文章解释说CLR在进程执行期间从不刷新环境。
我尝试的第三种方法是使用特定于平台的API加载本地库,例如Windows上的LoadLibrary()
和Linux上的dlopen()
,然后Dllimport
可能会发现具有相同名称的库已经加载,然后它将使用加载库来查找函数指针,就像这篇文章所做的那样。 我得到了同样的结果。 该问题的最佳答案是,我们可以编写一个封装类,它使用特定于平台的API来显式加载库并获取函数指针,而不是一种聚焦Dllimport
的方法,但这不是我想要的。
如果我的猜测是正确的,根据mono的文档, DllImportAttribute
在运行时内部调用LoadLibrary
或dlopen
以将库加载到内存空间。 因此它遵循特定OS平台的搜索规则,例如windows:
GetSystemDirectory()
函数获取此目录的路径。 GetWindowsDirectory()
函数获取此目录的路径。 和Linux:
LD_LIBRARY_PATH
环境变量中以冒号分隔的目录列表。 这是一种通过CLI程序可以找到本地共享库的常用方法。 /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
)。 /lib
,然后是/usr/lib
。 顺便说一句,我也尝试在运行时设置LD_LIBRARY_PATH
,但它不起作用,因为LD_LIBRARY_PATH
在进程启动时仅会被解析一次,这与Windows上的PATH
环境变量类似。
所以我的问题是:
SetDllDirectory()
的作用? DllImportAttribute
在Mono中实际做了什么? DllImport
而不是特定于平台的API(如LoadLibrary()
和dlopen()
? 不幸的是,答案是这种行为在Linux上的Mono和Windows上的.Net上是不同的,所以你只需要处理这个问题。
最好的选择是,如果你知道每个DLL的位置(例如你可以把它放在配置文件中),就是使用LoadLibrary
或dlopen
自己明确加载每个DLL。 这必须在第一次调用DllImport
函数之前完成。 DllImport
然后不需要指定路径。
这样你就知道你正在得到哪个DLL,并且可以按照任何正确的顺序加载它们,如果这是个问题。
如果由于某种原因,你真的不想这样做,我建议你创建一个像MySetDllDirectory
这样的函数,它在Windows上调用SetDllDirectory
并在Linux上设置LD_LIBRARY_PATH
。 通过这种方式,可以将更改隔离到单个模块。