我有托管 clr 的 C++ 代码,以便使用用 c# 编写的 Managed.dll。
这个 .net 有一个类似下面的方法,它允许代码注册事件通知:
public void Register(IMyListener listener);
界面看起来像这样
public interface IMyListener
{
void Notify(string details);
}
我想在程序的 C++ 部分做一些事情,由 .net 世界中的事件触发。如果有必要,我什至不介意为了使 Managed.dll 对 C++ 更友好而创建另一个托管 dll。
我在这里有什么选择?我确信我可以实现的唯一一个是:
- 编写另一个托管 dll 来监听这些事件,将它们排队并让 C++ 代码通过轮询访问队列
这当然会从“中断”样式变为“轮询”样式,具有所有优点和缺点以及提供排队的需要。我们可以不进行轮询吗?我可以以某种方式调用托管代码并为其提供一个指向 C++ 世界的函数指针作为参数吗?
更新 感谢 stijn 的回答和评论,我希望我朝着正确的方向前进了一点,但我想仍然存在的主要问题是如何将 fn 指针从非托管土地传递到 clr 托管环境。
假设我有一个“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 的指针传递给托管世界的方式似乎有问题,或者我的函数是如何定义的。当使用 String^ 参数而不是 fn ptr 时,我可以成功调用 CLR 函数。