gpt4 book ai didi

c# - 将带有参数的 c# 回调方法传递给 c++ dll 会导致 System.ExecutionEngineException

转载 作者:行者123 更新时间:2023-12-02 10:15:50 26 4
gpt4 key购买 nike

我正在使用 c++ dll 进行一些后台计算,我试图让它向我的调用报告进度C#代码。

为此,我注册了一个接受 StringBuilder 的回调方法。作为参数(在网上发现这是一种正确的做法)。

这是我的“c++”代码:

// --------------------------------------------
// ----------------- C++ CODE -----------------
// --------------------------------------------
// ----------------- dll api methods
// a custom class to contain some progress report stuff... basically, most important is
// that it contains the callback as ProgressCallback _callback;
CustomEventHandler* _eventHandler = NULL;

// definition of the callback type
typedef void(__stdcall* ProgressCallback)(char* log);

// method to register the callback method
int __stdcall SetCallbackFunction(ProgressCallback callback) {
// from https://stackoverflow.com/a/41910450/2490877
#pragma EXPORT_FUNCTION
// I encapsulated the callback into a custom class
_eventHandler = new CustomEventHandler();
_eventHandler->setEventHandler(callback);
// test all is ok => no problem at this stage, all works great, the
// passed-in callback is called with correct message.
logToCallback("All is ok while testing the method. So far so good!!");
return 0;
}

// the long and slow method (note that I might call it several times from c# during the
// one run
int __stdcall DoLooongStuff() {
// from https://stackoverflow.com/a/41910450/2490877
#pragma EXPORT_FUNCTION
// ------ this is a LOOOONG method that regualrly logs stuff via the callback,
// here an example....
char buf[1000];
sprintf_s(buf, "This is a sample progress log with some formats :%i %i %g", 1, 2, 3.1415);
logToCallback(buf);
// --- the above works a few times without any problem
return 0;
}

//--- this is a static method I use to send progress messages back
static void logToCallback(char* message) {
if (_eventHandler) {
_eventHandler->logToCallback(message);
}
}

// --------------- CustomEventHandlerClass
// ------- class declaration ------
class CustomEventHandler {
public:
void setEventHandler(ProgressCallback callback);
void logToCallback(char* message);
protected:
ProgressCallback _callback;
}

// ----- class implementation
// set the callback method
void CustomEventHandler::setEventHandler(ProgressCallback callback) {
_callback = callback;
}
void CustomEventHandler::logToCallback(char* message) {
if (_callback) {
_callback(message); // <========= this is where the debugger stops:
// no more info than the annoying System.ExecutionEngineException...
// I've tried to pass a constant message like "1234" but got the same issue...
//_callback("1234");
// if however I remove the call to the callback, I don't get errors
// (I know this doesn't mean I don't have any...)
}
}

现在对于调用 c# 代码,我使用以下代码:
// --------------------------------------------
// ----------------- C# CODE ------------------
// --------------------------------------------
// ----- the delegate type to be passed to the dll
public delegate bool CallbackFunction([MarshalAs(UnmanagedType.LPStr)] StringBuilder log);


// ----- prepare to load the dll's methods (I only show the SetCallback code here, other api methods
// are declared and loaded the same way)
private delegate int _SetCallbackFunction_(CallbackFunction func);
private _SetCallbackFunction_ SetCallbackFunction_Dll;

public int SetCallbackFunction(CallbackFunction func) {
return SetCallbackFunction_Dll(func);
}

// loading methods
private T GetDelegate<T>(string procName) where T : class {
IntPtr fp = GetProcAddress(_dllHandle, procName);
return fp != IntPtr.Zero ? Marshal.GetDelegateForFunctionPointer(fp, typeof(T)) as T : null;
}

async Task loadDllMethods() {
// load the delegates => great, it works!
SetCallbackFunction_Dll = GetDelegate<_SetCallbackFunction_>("SetCallbackFunction");
// set callback in DLL, calls the delegate once successfully...
SetCallbackFunction(cSharpCallback);
await doTask();
}

async Task doTask() {
// start the long dll method, that fires the callback to monitor progress
while (someConditionIsMet) {
DoLooongStuff(); // => calls the dll with registered callback!
}
}


// the actual callback
bool cSharpCallback(StringBuilder strBuilder) {
// this is called a few times successfully with the expected message!
Console.WriteLine(strBuilder.ToString());
return true;
}

我搜索了不同的线程以找出错误。由于“buf”尺寸太小,我遇到了一个错误,所以我只是确保它足够大。我还发现 '&_callback' 总是指向同一个地方(它是!)。

我没有搜索选项,任何帮助将不胜感激。请注意,我是 dll 集成、编码等方面的专家,我把引用资料放在了我找到提示的地方!

最佳答案

只要在 C++ 中使用回调,您就需要确保传递给 C++ 的委托(delegate)是事件的。只要使用相应的 C++ 回调,您就有责任保持委托(delegate) C# 对象处于事件状态:

someField = new CallbackFunction(cSharpCallback);
SetCallbackFunction(someField);

更好的是,只需使用 Scapix Language Bridge ,它会完全自动生成 C++ 到 C# 的绑定(bind)(包括回调)。免责声明:我是 Scapix Language Bridge的作者.

关于c# - 将带有参数的 c# 回调方法传递给 c++ dll 会导致 System.ExecutionEngineException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61985465/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com