アンマネージ コードを使用するクロスプラットフォーム .NET ライブラリを作成しています。私のクラスの静的コンストラクターでは、プラットフォームが検出され、適切なアンマネージ ライブラリが埋め込みリソースから抽出され、temp ディレクトリに保存されます。
ライブラリが PATH にないときに見つけられるように、一時ファイルに保存した後に明示的にロードします。Windows では、これLoadLibrary
は kernel32.dll から正常に動作します。私はdlopen
Linux で同じことをしようとしていますが、DllNotFoundException
後で P/Invoke メソッドをロードするときにエラーが発生します。
ライブラリ「libindexfile.so」が一時ディレクトリに正常に保存され、呼び出しがdlopen
成功することを確認しました。私は何が起こっているのかを理解するためにmono ソースを掘り下げました。それは、次の への呼び出し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);
}
アップデート:
on 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
、2 回目の呼び出しは失敗します。これは、同じ名前のライブラリが同じパスにあると想定していないためです。これを回避する方法はありますか?