我有托管clr的C++代码,以便使用C#编写的Managed.dll。允许托管环境中的托管代码回拨非托管代码
这.Net有类似下面的方法,它允许代码,以注册事件通知:
public void Register(IMyListener listener);
界面看起来是这样的
public interface IMyListener
{
void Notify(string details);
}
我想要做的东西在程序的C++部分中,由.net世界中的事件触发。如果必要,我甚至不介意创建另一个托管dll,以使Managed.dll更适合C++ - 友好的唯一目的。
我在这里有什么选择?唯一的一个,我相信我可以实现的是:
- 写另一个托管DLL侦听这些事件,队列它们并通过轮询让C++代码访问队列
这当然会从“中断”风格转变为“轮询”风格,具有所有优点和缺点,并且需要提供排队。我们可以不用投票吗?我能否以某种方式调用托管代码并将其作为参数提供给C++世界的函数指针?
更新 由于斯泰恩的答案和意见,我希望我搬到了正确的方向了一点,但我想主要的问题仍然是开放的是如何从非托管土地FN指针传递到CLR托管环境。
说我有一个 “INT(INT)FN” 类型的函数指针,我想传递给管理世界,这里有相关部分:
托管代码(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的指针传递到托管的世界,或者我的函数是如何定义的方式似乎有些不对。当使用String^param而不是fn ptr时,我可以成功调用CLR函数。
你的CLI方法需要'native_fun&'但是你传递'native_fun',这可能是问题吗?你是否尝试过传递指针(例如'native_fun *')?你可以附加一个调试器(最终通过在某处放置一个“DebugBreak”)并查看该参数的值是否正确传递? – stijn