这种方式比较简单,给大家分享一下,同时讲一下SafeArray内定义结构体的方法

1. 需求描述

需求是这样的,C++代码和C#代码相互通信(C++一般做服务,C#做客户端),C++一侧准备好数据,然后发给C#端解析,这种需求还是比较常见的。

但是由于数据比较复杂,是一个数据结构,还可能数据结构里套用数据结构,总之数据很复杂(其实我觉得使用xml字符串传递比较理想,兼容性也比较好,但作为程序员有时候没有选择的权利)

2. 定义COM文件,idl文件

对于这个文件不熟悉的自己百度谷歌查查吧。

首先在文件里定义回调接口,也就是C#端需要继承的接口

[object, uuid, oleautomation,helpstring,...] // 内容自己填吧

interface IDataEvent : IUnknown{

  HRESULT OnDataEvent([in] SAFEARRAY(struct SData)* psaDataList);

};

其次定义C++导出接口,也就是C++端需要继承的接口

[object, uuid, dual, nonextensible,...]

interface IDataServer : IDispatch{

  ......

  [id(n)] InitCallback([in] IDataEvent* pCallback);  // 你也可以改为AddListener什么的

};

然后需要定义你的结构体和相关的其他信息

[uuid...]

library DataServer{

  enum EnumType{

    XXX_YYY = 0x01,......

  };

  [uuid...]

  struct SData{

    BSTR name;

    LONGLONG time;  // 使用longlong表示filetime,这个里边不仅有年月日十分秒,还有毫秒信息,更重要的是UTC时间

    VARIANT saValueList;  // 在C#端变成object,根据具体的类型再强转吧,或者在C#端一直保持object类型的状态,你也可以直接使用double或BSTR等类型

    SAFEARAY(xxxx) saList;  // 定义你自己的类型,别忘了xxxx需要定义好哦!

  };

  ......

};

这个文件编译时会生成tlb文件,交给C#直接添加reference就可以啦,如果添加失败,可以手动转换,使用.NET提供的编译工具“Tlbimp”,命令行参考如下

tlbimp myLib.tlb /out:myLib.dll

也可以直接在代码里import这个tlb文件,只不过使用tlb里导出的类型有点不太方便。

3. C#端处理

一般的处理过程是这样的

(1)启动部分,通过各自的手段获得C++端提供的服务对象,将其强转成导出接口对象IDataServer

(2)自己创建一个类用于接受数据 class DataClient : IDataEvent,调用IDataServer的注册回调的函数,将DataClient对象传给C++端

(3)在DataClient类中实现这个函数 public void OnDataEvent(ref Array psaDataList),解析数据吧,遍历Array,将内容强转成SData

这里需要注意的是,一般服务端返回数据时,由于数据量可能比较大,都是通过一个子线程完成的,所以C#端的这个OnDataEvent函数需要判断当前是否是UI线程,如果不是的话,不要直接改变UI,这可能导致UI锁住,正确的做法使用异步处理方式,比如将数据缓存起来,等待UI处理,或者使用UI.InvokeRequired方法与UI抢控制权,然后再处理UI。

4. C++端处理数据

C++端填充数据的过程是这样的

CComPtr<IRecordInfo> pRecord;
GetRecordInfoFromGuids(LIBID_xxx, 1, 0, ::GetUserDefaultLCID(), __uuid(SData), &pRecord);
......
SAFEARAY *psa = ::SafeArrayCreateEx(VT_RECORD, 1, &bound, pRecord);
::SafeArrayAccessData(psa, (void**)&pList);
...... // fill data
::SafeArrayUnaccessData(psa);

CSharpObj->OnDataEvent(&psa); // send to C# object

::SafeArrayAccessData(psa, (void**)&pList);
...... // release data
::SafeArrayUnaccessData(psa);
::SafeArrayDestory(psa);

浅尝辄止——在C++中调用C#的回调函数——COM方式的更多相关文章

  1. 关于as中的事件与回调函数

    对于Observer模式, 在as中object(被观察者)既可以用事件(event),也可以用回调函数(caller)来通知观察者(observer).那在实际的开发中到底应该选择用event还是用 ...

  2. C语言中的回调函数(Callback Function)

    1 定义和使用场合 回调函数是指 使用者自己定义一个函数,实现这个函数的程序内容,然后把这个函数(入口地址)作为参数传入别人(或系统)的函数中,由别人(或系统)的函数在运行时来调用的函数.函数是你实现 ...

  3. [转]理解与使用Javascript中的回调函数

    在Javascript中,函数是第一类对象,这意味着函数可以像对象一样按照第一类管理被使用.既然函数实际上是对象:它们能被“存储”在变量中,能作为函数参数被传递,能在函数中被创建,能从函数中返回. 因 ...

  4. C++中回调函数(CallBack)的使用

    如果试图直接使用C++的成员函数作为回调函数将发生错误,甚至编译就不能通过. 其错误是普通的C++成员函数都隐含了一个传递函数作为参数,亦即“this”指针,C++通过传递this指针给其成员函数从而 ...

  5. 【JavaScript】理解与使用Javascript中的回调函数

    在Javascript中,函数是第一类对象,这意味着函数可以像对象一样按照第一类管理被使用.既然函数实际上是对象:它们能被“存储”在变量中,能作为函数参数被传递,能在函数中被创建,能从函数中返回. 因 ...

  6. C语言中的回调函数

    C语言中通过函数指针实现回调函数(Callback Function) ====== 首先使用typedef定义回调函数类型 ======  typedef void (*event_cb_t)(co ...

  7. 如何在Java中调用Python代码

    有时候,我们会碰到这样的问题:与A同学合作写代码,A同学只会写Python,而不会Java, 而你只会写Java并不擅长Python,并且发现难以用Java来重写对方的代码,这时,就不得不想方设法“调 ...

  8. 理解 JavaScript 回调函数并使用

    JavaScript中,函数是一等(first-class)对象:也就是说,函数是 Object 类型并且可以像其他一等对象(String,Array,Number等)一样使用.它们可以"保 ...

  9. C++ 回调函数的定义与用法

    一回调函数 我们经常在C++设计时通过使用回调函数可以使有些应用(如定时器事件回调处理.用回调函数记录某操作进度等)变得非常方便和符合逻辑,那么它的内在机制如何呢,怎么定义呢?它和其它函数(比如钩子函 ...

随机推荐

  1. Magento table rates表运费设置

    在magento中集成了Table rate表运费,这种运输方式.表运费就是我们自己写个运费表,根据距离和商品重量设置运费,制做成一张csv格式的表,导入到magento中,来实现运费的控制. 在我的 ...

  2. 关于vue.js中表单控件绑定练习

    html: <!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8 ...

  3. git入门到熟练使用

    最近以为接触ios开发,所以对git也产生了一点兴趣.所以在网上搜索资料开始学习,但大部分都是没用的copy的文章,有一个还不错的,推荐给大家 http://www.liaoxuefeng.com/w ...

  4. ASP.NET 5探险(8):利用中间件、TagHelper来在MVC 6中实现Captcha

    (此文章同时发表在本人微信公众号"dotNET每日精华文章",欢迎右边二维码来关注.) 题记:由于ASP.NET 5及MVC 6是一个微软全新重新的Web开发平台,之前一些现有的验 ...

  5. 【堆栈应用一】一个数divided=几个最小质因数的乘积(时间复杂度On)

    此算法由LQD提供

  6. 第五天:内置对象(7.Javascript内置对象)

    1)中所术是内置对象,2)中为自定义对象 代码说明如下 2.1.1 定义并创建对象实例方式1,代码如下: <!DOCTYPE html><html lang="en&quo ...

  7. ecshop 无限分类解析(转)

    对ecshop无限级分类的解析,认真分析后发现真的其算法还是比较精典的其实并不难理解,有举例方便大家理解 function cat_options($spec_cat_id, $arr) { stat ...

  8. CSS3 text-rendering属性

    这种非标准的属性目前不被推荐.我们一般会找一个可以替代的方法来完成相同的功能,不到外不得已,最好别用.   CSS的这个text-rendering属性通常被用在Windows和Linux系统中,用来 ...

  9. HBase-配置说明

    转载自:http://www.aboutyun.com/thread-7914-1-1.html hbase.rootdir这个目录是region  server的共享目录,用来持久化Hbase.UR ...

  10. java几种字符串反转

    java实现的字符串翻转,能想到的这几种方法 假设有其它方法,欢迎交流 //字符串反转 public class ReverseString { public String reverse1(Stri ...