永发信息网

andle::Invoke”类型的已垃圾回收委托进行了回调

答案:2  悬赏:40  手机版
解决时间 2021-11-07 19:08
andle::Invoke”类型的已垃圾回收委托进行了回调
最佳答案
手头有个C++的DLL,是公司的一个远程通话功能组件。长久以来,这个DLL对外只有三个操作接口。而从合理的角度来说,这个DLL本应再提供一些回调接口或事件之类的东西,用于在通话状态被动改变时通知外层应用程序。不过银行里的规矩多多,不能用ActiveX;而使用回调,却又似不那么的稳定,尤其在与C#交互时。所以才一直就这么用着。

直到最近,外层应用程序的开发人员提意见抱怨这个DLL。于是,一狠心,决定向这个DLL添加回调的支持。虽然不能确定之前使用回调不稳定的问题在哪,但现有资料和之前自己单独写的测试却都表明C#向C++传递的回调是可以正常工作的。因此,必定是这个DLL的什么地方存在错误才会不稳定,大不了搭上一个周末的时间,总应该能解决吧。

一般来说,实现回调的要点就两点:

1. 回调应加上WINAPI或CALL关键字,以声明其调用方式;

2. 注意参数类型尤其是长度,在C++和C#中的声明要一致;避免使用指针和引用类型。

由于之前已经单独测试过,所以就差在DLL中实战演练了。花了一天时间,根据他们的要求改好了程序。为了避免遇到传说中的住在迷宫里的那个会吃迷路的人的魔鬼。其间还打了几针预防针,先在定义回调时先排除了任何字符参数,只用整数;然后去掉了之前的那个中间DLL。原来的核心DLL是MFC扩展动态链接库,不能直接用在C#中,所以又在外边套了个正规DLL。虽然间接调用DLL很正常,但让结构更简单,总没有坏处。

一切妥当,开始调试,改掉几个小问题后,发现程序竟然正常的跑起来了,回调的输出欢快的显示到屏幕上了。又各式各样的环境各测了几遍,依然OK,看来这次运气不差,哈。接下来打包,写接口和回调说明文档,画状态图。

在发出去前,想起来又改了改一些调试和日志信息,然后又神经质的测试了一把。事后证明,这是一个让人后悔也庆幸的动作。因为,这次遇到Demo的老兄Demon了,哎,怎一个惨字了得.....

幸亏本命年的我早有时刻面对打击的觉悟,早前没有得意忘形,要不这下心情落差大去了。额,不过,来就来吧,有周末两天做后盾,不信搞不定你。

看看Demon老兄说了些啥:SYSTEM.WINDOWS.FORMS.NI.DLL 0xC0000005 access violation。

完全摸不着头脑,只能慢慢来了。

先检查了一遍DLL程序,应该没有问题,所有的回调也都是在主线程上触发的,应该跟线程也没有关系。

再来确定到底是C++ DLL的还是C# EXE的问题,把DLL和EXE在DEBUG和Release下各编译了一份,然后组合运行了一下,发现当且仅当使用EXE的Release版程序时,会出现该异常。那么,就应该是C#程序的问题了。

这只是一个非常简单的示例,实在想不明白代码可能会有什么问题。而且还是Debug正常,Release异常。先改改编译选项试试,把Optimze Code关了试试,问题照旧;再把Define Debug constant开了,这就跟Debug版本的编译选项完全一样了,还是不行。看来此路不通了。

看看Google同学有没有遇到过这样的问题,把Demon老兄说的搜了一下,结果没有相关资料…看来这下有得头疼了。

忽然想起似乎刚才DLL和EXE组合测试的时刻似乎出过一个挺不寻常的提示。再去找找看,发现Debug版的DLL和Release版的EXE一起运行会有这样的提示:

File: i386\chkesp.c
Line: 42

The value of ESP was not properly saved across a function call. This is usually a result of calling a function declared with one calling convention with a function pointer declared with a different calling convention.

再搜索一下,这次倒有不少同样不幸的人,不过正如那句话“不幸的人各有各的不幸”,他们的原因似乎跟我的情况扯不上啥关系。

这下没招了,再求助Baidu一下,看看大家用C++回调C#代码都遇到些啥情况。结果试了好几个关键字,都一无所获,正当我感觉鸭梨很大的时候,突然间,用关键字“C++ C# 回调 委托”搜到了一个有点意思的帖子 C#处理C++库回调报错_非托管代码传递委托被垃圾回收,虽然这位老兄什么都没说明,不过贴上来的异常内容很特别:

检测到 CallbackOnCollectedDelegate
Message: 对“HBVideoParser!Videocomm.Video.HB.HBSDK+SrcDataParseCBHandler::Invoke”类型的已垃圾回收委托进行了回调。这可能会导致应用程序崩溃、损坏和数据丢失。向非托管代码传递委托时,托管应用程序必须让这些委托保持活动状态,直到确信不会再次调用它们。

向C++传递的委托对象回垃圾回收了,导致回调时异常?感觉有点怪怪,不过死马当活马医吧,改Demo,传了一个全局委托对象给DLL,再测试~哈,回调输出又欢快滴出来了~

看来果真如此了,确认一下,改回原来的传递临时对象的方式,在Demo的Main函数里加个异常捕获,发现确实异常会传递到此处,内容则是“Object reference not set to an instance of an object”。虽然与上述的不一致,不过应该就是一回事啦。

现在想想,这也不难理解。C#中通过引用计数来判断对象是否可被回收,在Demo中,创建的临时委托对象只是被临时使用了一下,没有任何引用,虽然在C++ DLL中保存了,但俨然那已经不属于Demo的范围了。因此被垃圾回收很正常。

再想到之前自己单独写的测试似乎并没有发现这样的问题,那又是为什么呢?难道因为程序占用内在太少还没来得及进行垃圾回收操作?再去翻出来,点住调用按钮不放,果然,在输出三四十条信息之后程序异常了。
全部回答
看不懂
我要举报
如以上问答信息为低俗、色情、不良、暴力、侵权、涉及违法等信息,可以点下面链接进行举报!
大家都在看
有没有宝应到福建汽车票
浙江衢州龙葛线316省道0029KM+600M天池路段有
我今年17周岁 我想做流浪汉
7月1日新交通法对单轴货车是怎么规定的我6.8
斐讯推出的音乐风火轮有什么特点?
为什么晴天土壤温度日变化那么明显,而阴天变
P丽江金尚机动车检测有限公司办公地址在什么
怀集一中高中教师每月6000以上可信吗
羊角有用吗?
寻乌一梅洲多少公里
1100元5年能挣多少利息?
梅姓取名宝典四个字的
哪里有国外正宗古巴雪茄卖?
昆明市中医医院(呈贡院区)地址在什么地方,
雀巢拿铁丝滑咖啡的热量是多少
推荐资讯
csol什么时候还会有灭灵升级的活动
大珠小珠落玉盘是什么乐器
谁有英雄联盟的作弊秘籍
麻栗坡县交警大队科目三考试路段地址在哪,我
牛口村地址在什么地方,想过去办事,
第一次玩航拍 这个DJI的摄像头很松 正常吗
阅读理解.in 1972,i returned to miami beach
迪鑫(长城4S)地址在哪,我要去那里办事
sun英文是什么意思
榴莲在南方卖多少钱哪?
高瀚宇和季肖冰在一次采访中提到2015年有合作
诗句六月荷花香满湖,红衣绿扇映清波是什么意
正方形一边上任一点到这个正方形两条对角线的
阴历怎么看 ?