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