我有託管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