我正在编写一个跨平台的.NET库,其中包含一些非托管代码。在我的类的静态构造函数中,检测平台并从嵌入资源中提取适当的非托管库并保存到临时目录,类似于另一个stackoverflow答案中给出的代码。
为了在未在PATH中找到库的情况下仍然可以找到它,我将其保存到临时文件后明确加载它。在Windows上,使用kernel32.dll中的LoadLibrary很好用。我试图在Linux上使用dlopen做同样的事情,但是当它需要加载P/Invoke方法时,我会遇到DllNotFoundException异常。
我已经验证了库“libindexfile.so”已成功保存到临时目录,并且调用dlopen也成功了。我深入研究了Mono源码,尝试弄清楚发生了什么,我认为这可能归结于后续调用dlopen是否只是重复使用先前加载的库。(当然假设我的对Mono源代码的浏览能够得出正确的结论)。
这就是我正在尝试做的事情的大致形状:
为了在未在PATH中找到库的情况下仍然可以找到它,我将其保存到临时文件后明确加载它。在Windows上,使用kernel32.dll中的LoadLibrary很好用。我试图在Linux上使用dlopen做同样的事情,但是当它需要加载P/Invoke方法时,我会遇到DllNotFoundException异常。
我已经验证了库“libindexfile.so”已成功保存到临时目录,并且调用dlopen也成功了。我深入研究了Mono源码,尝试弄清楚发生了什么,我认为这可能归结于后续调用dlopen是否只是重复使用先前加载的库。(当然假设我的对Mono源代码的浏览能够得出正确的结论)。
这就是我正在尝试做的事情的大致形状:
// actual function that we're going to p/invoke to
[DllImport("indexfile")]
private static extern IntPtr openIndex(string pathname);
const int RTLD_NOW = 2; // for dlopen's flags
const int RTLD_GLOBAL = 8;
// its okay to have imports for the wrong platforms here
// because nothing will complain until I try to use the
// function
[DllImport("libdl.so")]
static extern IntPtr dlopen(string filename, int flags);
[DllImport("kernel32.dll")]
static extern IntPtr LoadLibrary(string filename);
static IndexFile()
{
string libName = "";
if (IsLinux)
libName += "libindexfile.so";
else
libName += "indexfile.dll";
// [snip] -- save embedded resource to temp dir
IntPtr handle = IntPtr.Zero;
if (IsLinux)
handle = dlopen(libPath, RTLD_NOW|RTLD_GLOBAL);
else
handle = LoadLibrary(libPath);
if (handle == IntPtr.Zero)
throw new InvalidOperationException("Couldn't load the unmanaged library");
}
public IndexFile(String path)
{
// P/Invoke to the unmanaged function
// currently on Linux this throws a DllNotFoundException
// works on Windows
IntPtr ptr = openIndex(path);
}
更新:
似乎在Windows上对LoadLibrary
的后续调用会查看是否已经加载了相同名称的dll,然后使用那个路径。例如,在以下代码中,两次调用LoadLibrary
都将返回有效的句柄:
int _tmain(int argc, _TCHAR* argv[])
{
LPCTSTR libpath = L"D:\\some\\path\\to\\library.dll";
HMODULE handle1 = LoadLibrary(libpath);
printf("Handle: %x\n", handle1);
HMODULE handle2 = LoadLibrary(L"library.dll");
printf("Handle: %x\n", handle2);
return 0;
}
在Linux上使用dlopen
尝试相同的操作会失败,因为它不会假设同名库位于相同路径下。有没有什么方法可以解决这个问题?