How to set search path for dllimport in mono?

I'm developing an Unity app which needs to dynamically load native libraries from outside where the app is installed, for some reason I cannot set the absolute path to DllImport before compiling (such as read the library path in a .txt at runtime and load it), and I don't want to use platform specific API such as LoadLibrary() on Windows or dlopen on Linux because it's inconvenient. And I have been struggled for several days.

I know that the search path can be adjusted by SetDllDirectory() on Windows from this post, and it works well when testing on .NET Framework applications. However, it does not work in Unity which is based on mono 2.0, it just throws DllNotFoundException at runtime, but it works fine when I use absolute path in DllImport or copy the dll into my Unity project (I'm sure that the code is same)

The next way I tried is environment variable, and it does not work on both .NET and Mono, this post explained that CLR never refreshes the environment during process execution.

The third way I tried is to load the native library with platform specific API such as LoadLibrary() on Windows and dlopen() on Linux first, and then Dllimport may find that the library with same name has already been loaded, then it will use the load library to find function pointers, just as this post did. And I get the same result. The top answer of that question says we can write a wrapper class which uses platform specific API to explicitly load library and get functions pointers, instead of an approach focusing Dllimport , but it is not what I want.

If my guess is right, according to mono's document, DllImportAttribute calls LoadLibrary or dlopen internally at runtime to load a library into memory space. So it follows the search rules of specific OS platform, for example windows:

  • The directory from which the application loaded.
  • The current directory
  • The system directory. Use the GetSystemDirectory() function to get the path of this directory.
  • The 16-bit system directory.
  • The Windows directory. Use the GetWindowsDirectory() function to get the path of this directory.
  • The directories that are listed in the PATH environment variable.
  • and Linux:

  • A colon-separated list of directories in the user's LD_LIBRARY_PATH environment variable. This is a frequently-used way to allow native shared libraries to be found by a CLI program.
  • The list of libraries cached in /etc/ld.so.cache . /etc/ld.so.cache is created by editing /etc/ld.so.conf and running ldconfig(8) . Editing /etc/ld.so.conf is the preferred way to search additional directories, as opposed to using LD_LIBRARY_PATH , as this is more secure (it's more difficult to get a trojan library into /etc/ld.so.cache than it is to insert it into LD_LIBRARY_PATH ).
  • /lib , followed by /usr/lib .
  • By the way, I also tried to set LD_LIBRARY_PATH at runtime, but it does not work because LD_LIBRARY_PATH will be parsed only once when a process started, which is similar to PATH environment variable on Windows.

    So my question is:

  • Why does the same code performs differently on .NET Framework and Mono? Does Mono just ignore the effect of SetDllDirectory() on Windows? What does DllImportAttribute actually do in Mono?
  • Is there any way to adjust search path for Unity/Mono apps at runtime, just using DllImport rather than platform specific APIs such as LoadLibrary() and dlopen() ?

  • Unfortunately the answer is that this behaviour is different between Mono on Linux, and .Net on windows, so you are just going to have to deal with that.

    The best option, if you know where each DLL is located (eg you can put this into a config file), is to load each one explicitly yourself using LoadLibrary or dlopen . This must be done prior to the first call to a DllImport function. DllImport then need not specify a path.

    This way you know exactly which DLL you are getting, and can load them in whatever order is correct, if this is an issue.

    If for some reason you really don't want to do that, I suggest you create a function like MySetDllDirectory which on Windows calls SetDllDirectory and on Linux sets LD_LIBRARY_PATH . In this way the changes can be isolated to a single module.

    链接地址: http://www.djcxy.com/p/7754.html

    上一篇: 将Silverlight DataGrid.Celltemplate绑定到ViewModel

    下一篇: 如何设置单声道dllimport的搜索路径?