Managed.dll を使用するために clr をホストする C# で記述された C++ コードがあります。
この .net には、次のようなメソッドがあり、コードでイベントの通知を登録できます。
public void Register(IMyListener listener);
インターフェースはこんな感じ
public interface IMyListener
{
void Notify(string details);
}
.net の世界でのイベントによってトリガーされる、プログラムの C++ 部分で何かをしたいと思います。必要に応じて、Managed.dll をより C++ に適したものにするためだけに、別のマネージド DLL を作成してもかまいません。
ここでのオプションは何ですか? 私が実装できると確信しているのはこれだけです:
- これらのイベントをリッスンし、それらをキューに入れ、C++ コードがポーリングを介してキューにアクセスできるようにする別のマネージ DLL を作成します。
もちろん、これは「割り込み」スタイルから「ポーリング」スタイルに変わり、すべての長所と短所、およびキューイングを提供する必要があります。ポーリングなしでできますか?どうにかしてマネージ コードを呼び出し、引数として C++ の世界への関数ポインターを提供することはできますか?
更新 stijnの回答とコメントのおかげで、正しい方向に少し進んだことを願っていますが、まだ未解決の主な問題は、管理されていない土地からclrホスト環境にfnポインターを渡す方法だと思います。
「int fn(int)」タイプの関数ポインターをマネージド ワールドに渡したいとします。関連する部分は次のとおりです。
マネージド コード(C++/CLI)
typedef int (__stdcall *native_fun)( int );
String^ MyListener::Register(native_fun & callback)
{
return "MyListener::Register(native_fun callback) called callback(9): " + callback(9);
}
アンマネージ コード
typedef int (__stdcall *native_fun)( int );
extern "C" static int __stdcall NativeFun(int i)
{
wprintf(L"Callback arrived in native fun land: %d\n", i);
return i * 3;
}
void callCLR()
{
// Setup CLR hosting environment
...
// prepare call into CLR
variant_t vtEmpty;
variant_t vtRetValue;
variant_t vtFnPtrArg((native_fun) &NativeFun);
SAFEARRAY *psaMethodArgs = SafeArrayCreateVector(VT_VARIANT, 0, 1);
LONG index = 0;
SafeArrayPutElement(psaMethodArgs, &index, &vtFnPtrArg);
...
hr = spType->InvokeMember_3(bstrMethodName, static_cast<BindingFlags>(
BindingFlags_InvokeMethod | BindingFlags_Static | BindingFlags_Public),
NULL, vtEmpty, psaMethodArgs, &vtRetValue);
if (FAILED(hr))
wprintf(L"Failed to invoke function: 0x%08lx\n", hr);
spType->InvokeMember_3
呼び出しは結果につながります0x80131512
。
NativeFun へのポインターをマネージ ワールドに渡す方法、または関数の定義方法に問題があるようです。fn ptr の代わりに String^ param を使用すると、CLR 関数を正常に呼び出すことができます。