C#/.NET 3.5 アプリケーションを開発しています。C で記述されたレガシー dll、signals.dll を使用しています。P/Invoke を使用して .NET ラッパーから呼び出します。タイプ A とタイプ B の 2 種類の処理関数を呼び出しています。1 種類の処理のみを呼び出すと、すべて正常に動作します。A 処理と B 処理の呼び出しをインターリーブすると、データ結果が破損します。dll、signals.dll が C スタイルのグローバル変数を使用しており、データが破損していると思われます。
これを解決するために、ディスク上に dll の 2 つのコピー、signals.dll と signals2.dll を作成しました。次に、P/Invoke を使用して .NET ラッパーを変更し、タイプ A の処理を 1 つの dll に、タイプ B の処理を別のインスタンスに指示しました。そして今、すべてが正常に動作します。
次に、フォーラムで同様の問題とそこでの解決策を見ました。(グローバル データを使用してプラグイン DLL の複数のインスタンスをサポートする)。基本的に、その提案されたソリューションはコードから動的に配置され、(必要に応じて) ディスク上に .dll の新しいインスタンスを作成し、それをロードしてそこから関数を呼び出します。コードの主要部分は次のようになります。
private IntPtr dllHandle;
string myDllPath = Path.Combine(dllDir, String.Format("mylib-{0}.dll", GetHashCode()));
File.Copy(origDllPath, myDllPath);
dllPath = myDllPath;
dllHandle = LoadLibrary(dllPath);
_getVersion = GetProcEntryDelegate<_getVersionDelegate>(dllHandle, "GetVersion");
private delegate int _getVersionDelegate();
private readonly _getVersionDelegate _getVersion;
public int GetVersion()
{
return _getVersion();
}
private static D GetProcEntryDelegate<D>(IntPtr hModule, string name)
where D: class
{
IntPtr addr = _getProcAddress(hModule, name);
if (addr == IntPtr.Zero)
throw new Win32Exception();
return Marshal.GetDelegateForFunctionPointer(addr, typeof(D)) as D;
}
私の頭に浮かぶのは、上記のコードを変更して、ディスクではなくメモリー内にdllのコピーを作成し、そこからロードすることは可能でしょうか。LoadLibrary からではなく、メモリから値を取得するには、IntPtr dllHandle を騙す必要があると思います。どうやってするか?