【发布时间】:2012-11-07 20:35:52
【问题描述】:
我正在编写一个使用一些非托管代码的跨平台 .NET 库。在我的类的静态构造函数中,检测到平台并从嵌入式资源中提取适当的非托管库并保存到临时目录,类似于another stackoverflow answer 中给出的代码。
为了使库不在 PATH 中时可以找到,我在将其保存到临时文件后显式加载它。在 Windows 上,这适用于 kernel32.dll 中的LoadLibrary。我正在尝试在 Linux 上对 dlopen 执行相同的操作,但稍后在加载 P/Invoke 方法时会得到 DllNotFoundException。
我已验证库“libindexfile.so”已成功保存到临时目录,并且对dlopen 的调用成功。我深入研究了mono source 以试图弄清楚发生了什么,我认为这可能归结为对dlopen 的后续调用是否只会重用以前加载的库。 (当然假设我天真地通过单声道来源得出了正确的结论)。
这是我想要做的形状:
// 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 进行相同操作,第二次调用将失败,因为它不会假定同名库位于同一路径。有没有办法解决这个问题?
【问题讨论】: