如何解决C#调用C/C++DLL回调函数导致内存崩溃的问题-创新互联
问题描述:
成都创新互联不只是一家网站建设的网络公司;我们对营销、技术、服务都有自己独特见解,公司采取“创意+综合+营销”一体化的方式为您提供更专业的服务!我们经历的每一步也许不一定是最完美的,但每一步都有值得深思的意义。我们珍视每一份信任,关注我们的做网站、成都网站设计质量和服务品质,在得到用户满意的同时,也能得到同行业的专业认可,能够为行业创新发展助力。未来将继续专注于技术创新,服务升级,满足企业一站式成都营销网站建设需求,让再小的品牌网站设计也能产生价值!1. C/C++ 写的 DLL,其中有个方法(如MethodA)有的参数是回调函数。
2. C# 调用 DLL的方法MethodA,将自己的一个内部方法(InnerMethod)作为回调函数的地址传递过去。
3. 当 InnerMethod 被触发时,往往第一次能成功,再次触发时就会崩溃,报的错误为非法内存访问之类。
碰到以上错误,估计你的大脑也会像内存一样:奔溃。可能会尝试各种办法:修改 C/C++ 代码,将方法加上 _stdcall;修改 C# 代码,调整调用约定;修改 InnerMethod,增加各种调试,改用临时变量,改用全局变量,只做计算,不访问其它资源。。。最后呢,还是奔溃。
我当时就被这个问题折磨了好几天,而同事的 QT 调用 DLL 却正常,这说明问题还是出在 C# 上。后来经过多方查找,发现是 C# 的GC的问题,是GC把C#内的回调函数回收了,当下次DLL再次调用这个函数时,就会触发非法内存访问的错误。
如何修复呢?强制GC保留它,等到最后才回收。一般,出问题的的代码如下:
///
/// 调用 DLL 的方法(参数为回调函数地址)
///
private void CallDll()
{
DllMethodA(OnCallBack);
}
///
/// 给 DLL 的回调函数
///
///
private void OnCallBack(int retValue)
{
Console.WriteLine($@"the return value from the dll is {retValue}");
}
将代码修改如下:
// 声明委托,
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate void MethodCallbackEvent(int i);
private static MethodCallbackEvent _callbackFunc = null;
private static GCHandle _gcHandle = new GCHandle();
///
/// 调用 DLL 的方法(参数为回调函数地址)
///
private void CallDll()
{
// 让 GC 保留,不回收这个回调函数
_callbackFunc = new MethodCallbackEvent(OnCallBack);
_gcHandle = GCHandle.Alloc(_callbackFunc);
DllMethodA(_callbackFunc);
}
///
/// 给 DLL 的回调函数
///
///
private void OnCallBack(int retValue)
{
Console.WriteLine($@"the return value from the dll is {retValue}");
}
///
/// 增加一个释放的方法,在合适的时候调用
///
private void ReleaseCallback()
{
if (_gcHandle.IsAllocated) { _gcHandle.Free(); }
}
你是否还在寻找稳定的海外服务器提供商?创新互联www.cdcxhl.cn海外机房具备T级流量清洗系统配攻击溯源,准确流量调度确保服务器高可用性,企业级服务器适合批量采购,新人活动首月15元起,快前往官网查看详情吧
分享文章:如何解决C#调用C/C++DLL回调函数导致内存崩溃的问题-创新互联
转载来源:http://azwzsj.com/article/ihddp.html