浅尝辄止——在C++中调用C#的回调函数——COM方式
这种方式比较简单,给大家分享一下,同时讲一下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方式的更多相关文章
- Unity C# 调用 C++ DLL 并在 DLL 中调用 C# 的回调函数
Unity C# 调用 C++ DLL 并在 DLL 中调用 C# 的回调函数~~~ 呵呵... 看着有点晕.. 再解释一下就是 在Unity中 使用 C# 调用 C++ 写的 DLL, 但是在 ...
- python中进程池和回调函数
一.数据共享 1.进程间的通信应该尽量避免共享数据的方式 2.进程间的数据是独立的,可以借助队列或管道实现通信,二者都是基于消息传递的. 虽然进程间数据独立,但可以用过Manager实现数据共享,事实 ...
- Python并发编程06 /阻塞、异步调用/同步调用、异步回调函数、线程queue、事件event、协程
Python并发编程06 /阻塞.异步调用/同步调用.异步回调函数.线程queue.事件event.协程 目录 Python并发编程06 /阻塞.异步调用/同步调用.异步回调函数.线程queue.事件 ...
- unity 在脚本B中调用脚本A的函数
一,在脚本B中调用脚本A的函数. 脚本A: //myFuncs.cs using UnityEngine;using System.Collections; namespace myFuncs{ ...
- C++ 使用回调函数的方式 和 作用。 持续更新
先看两个demo: 一.在类test1中调用函数print() ,把print()的函数指针传递给test1的函数指针参数 test1.h: #include <stdio.h> #inc ...
- 关于as中的事件与回调函数
对于Observer模式, 在as中object(被观察者)既可以用事件(event),也可以用回调函数(caller)来通知观察者(observer).那在实际的开发中到底应该选择用event还是用 ...
- PHP – 在类中使用array_filter时回调函数的问题
了一个类处理好友,其中有一个方法用来同步好友,而这个方法中需要从微博传来的关注列表和粉丝列表中,找到互相关注的用户,记录一下经验,主要还是关于回调函数. 按照我最初的理解,这样写就可以了 privat ...
- 基于Lwip协议栈中独立模式下回调函数的使用
一.使用Lwip协议独立模式开发 最近在STM32F4上边移植了Lwip,Lwip是一个小型开源的TCP/IP协议栈,有无操作系统的支持都可以运行.我当前只测试了TCP Server功能,然后对TCP ...
- JS与OC交互,JS中调用OC方法(获取JSContext的方式)
最近用到JS和OC原生方法调用的问题,查了许多资料都语焉不详,自己记录一下吧,如果有误欢迎联系我指出. JS中调用OC方法有三种方式: 1.通过获取JSContext的方式直接调用OC方法 2.通过继 ...
随机推荐
- Atom安装activate-power-mode插件(震动炫酷)
1.下载安装Atom,地址:https://atom.io/ 2.下载安装activate-power-mode插件,地址:https://github.com/JoelBesada/activate ...
- Atom编辑器添加eclipse快捷键
Settings - Keybindings - 点击"your keymap file" 'atom-text-editor': 'alt-/': 'autocomplete- ...
- 解决Oracle 11g ORA-01017错误代码
在oracle的之前版本时, 你的用户名密码是大小写不敏感的, 但在11g中, 数据库默认密码的大小写是敏感的, 于是我们就知道了一个事实, 那就是jdbc在给oracle密码时, 会将其变成大写,真 ...
- Network Alignment(网络比对)模型
两类模型: 第一类:two-steps method 先计算两个网络之间每两个结点的相似性,再从N1*N2对相似性中抽取N1对匹配(N1<=N2). 代表算法:IsoRank 第二类:obj ...
- java编译期优化
java语言的编译期其实是一段不确定的操作过程,因为它可以分为三类编译过程: 1.前端编译:把.java文件转变为.class文件 2.后端编译:把字节码转变为机器码 3.静态提前编译:直接把*.ja ...
- 读取其他软件listview控件的内容
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; usin ...
- Process的Waitfor() 引起代码死锁
Java用process调用c#的exe后,process.waitfor(). exe执行会停在某处.据说是waitfor引起的exe子线程死锁. 先存一个链接 http://yearsaaaa12 ...
- 关于databinding的细节
原文在此:http://www.codeproject.com/Articles/24656/A-Detailed-Data-Binding-Tutorial 完整译文在此:http://www.cn ...
- 使用weave管理docker网络
weave简介 Weave creates a virtual network that connects Docker containers deployed across multiple hos ...
- laravel route路由
基本路由 您的应用程序的绝大多数路由将在 app/routes.php 文件中定义.Laravel 中最简单的路由由一个 URI 和一个闭包调用组成. 基本 GET 路由 代码如下: Route::g ...