实践:C++平台迁移以及如何用C#做C++包装层
作者:网络转载 发布时间:[ 2014/8/5 10:19:29 ] 推荐标签:C++ 平台迁移
如上定义一个宏定义,在导出的C++动态链接库中,可以选择项目属性里添加预处理器定义TRADITIONALDLL_EXPORTS,也或者是在引用这个文件加上.而在引用这个动态链接库不做处理.
先看一个普通的函数从非托管C++到C++/CRL到C#相应流程,这个函数是传入一个设备ID,得到设备的所有工程,以及默认的工程ID.
1 // C++
2 TRADITIONALDLL_API int GetTestList(const unsigned long deviceId, char** confs, int& count, int& defaultID);
3 TRADITIONALDLL_API int GetTestList(const unsigned long deviceId, char** confs, int& count, int& defaultID)
4 {
5 auto tests = PApi->Spider_GetTestList();
6 count = tests->count;
7 if (count > 0)
8 {
9 auto testNames = new char[32 * count];
10 memset(testNames, 0, 32 * count);
11 for (int i = 0; i < count; i++)
12 {
13 memcpy(testNames + i * 32, tests->driveArray[i].TestName, 32);
14 }
15 *confs = testNames;
16 defaultID = PApi->curModule->nDefaultID;
17 return FUNC_SUCCESS;
18 }
19 spiderAPI->errorStr = NotConnecteDev;
20 return 0;
21 }
22 // managed C++
23 bool GetTestList(const unsigned long deviceId, [Out]List <String^>^% testList, [Out]int% defalutID);
24 bool DeviceController::GetTestList(const unsigned long deviceId, [Out]List <String^>^% testList, [Out]int% defalutID)
25 {
26 testList = gcnew List<String^>();
27 char *nameBuffer = NULL;
28 int testCount = 0;
29 int dID = 0;
30 ::GetTestList(deviceId, &nameBuffer, testCount, dID);
31 defalutID = dID;
32 if (nameBuffer != NULL && testCount > 0)
33 {
34 char testName[32];
35 memset(testName, 0, 32);
36 for (int index = 0; index < testCount; ++index)
37 {
38 memcpy(testName, nameBuffer + index * 32, 32);
39 String^ str = gcnew String(testName);
40 testList->Add(str);
41 }
42 return true;
43 }
44 return false;
45 }
46 //C#
47 bool result = DeviceController.Instance.GetTestList(Device.Id, out testNames, out defaultID);
基本的传递如上,但是现在要求C#实时刷新设备转过来的数据,简单来说,是C++里socket接收线程收到设备发送的数据,需要通知C#界面刷新.看需求,C#里的事件能满足,但是是C++发送的消息,在这我们根据C++里的回调函数与托管代码里的事件结合来完成,去掉一些不必要的代码,主要过程如下.
1 // C++
2 typedef void (__stdcall *OnDataMessageRev)(const unsigned long deviceId, char* data, const int eventId,const int p0, const int p1,const int p2);
3
4 class Module
5 {
6 OnDataMessageRev onDataRev;
7 void didDataReceived();
8 void SetDataMessageCallback(OnDataMessageRev callback);
9 }
10 void Module::SetDataMessageCallback(OnDataMessageRev callback)
11 {
12 onDataRev = callback;
13 }
14 void Module::didDataReceived()
15 {
16 switch (dataMsg.Msg.nEventID)
17 {
18 case DSP_DISPNEXT_OK:
19 {
20 if (onDataRev)
21 onDataRev(this->deviceId, dataMsg.Data, dataMsg.Msg.nEventID, dataMsg.Msg.nParameters0, dataMsg.Msg.nParameters1, dataMsg.Msg.nParameters2);
22 }
23 break;
24 //...
25 }
26 }
27 DEVICEAPI_API void SetDataMessageCallback(OnDataMessageRev callback);
28 DEVICEAPI_API void SetDataMessageCallback(OnDataMessageRev callback)
29 {
30 model.SetDataMessageCallback(callback);
31 }
32 // managed C++
33 public delegate void DeviceDataMessageHandler(const unsigned long deviceId, const array<Byte>^ data, const int eventId, const int p0, const int p1, const int p2);
34 public delegate void DeviceDataCallback(const unsigned long deviceId, char* data, const int eventId, const int p0, const int p1, const int p2);
35 public ref class DeviceController
36 {
37 DeviceDataCallback^ dataCallback;
38 DeviceDataMessageHandler^ onDeviceDataReceived;
39 event DeviceDataMessageHandler^ DeviceDataReceived
40 {
41 void add(DeviceDataMessageHandler^ h)
42 {
43 onDeviceDataReceived += h;
44 }
45 void remove(DeviceDataMessageHandler^ h)
46 {
47 onDeviceDataReceived -= h;
48 }
49 }
50
51 DeviceController::DeviceController()
52 {
53 dataCallback = gcnew DeviceDataCallback(&(DeviceController::DataReceivedCallback));
54 IntPtr ptrData = Marshal::GetFunctionPointerForDelegate(dataCallback);
55
56 ::SetDataMessageCallback(static_cast<OnDataMessageRev>(ptrData.ToPointer()));
57 GC::KeepAlive(dataCallback);
58 }
59
60 void OnDeviceDataReceived(const unsigned long deviceId, const array<Byte>^ data, const int eventId, const int p0, const int p1, const int p2)
61 {
62 DeviceDataMessageHandler^ handler = onDeviceDataReceived;
63 if (handler != nullptr)
64 {
65 handler(deviceId, data, eventId, p0, p1, p2);
66 }
67 }
68 }
69
70 //C#
71
72 DeviceController.Instance.DeviceDataReceived += Instance_DeviceDataReceived;
73
74 T ByteArrayToStructure<T>(byte[] bytes, IntPtr pin, int offset) where T : struct
75 {
76 try
77 {
78 return (T)Marshal.PtrToStructure(pin + offset, typeof(T));
79 }
80 catch (Exception e)
81 {
82 return default(T);
83 }
84 }
85 private void Instance_DeviceDataReceived(uint deviceId, byte[] data, int eventId, int p0, int p1, int p2)
86 {
87 GCHandle handle = GCHandle.Alloc(data, GCHandleType.Pinned);
88 IntPtr pin = handle.AddrOfPinnedObject();
89 int nCheckNum = ByteArrayToStructure<int>(data, pin, offset);
90 DISPLAYPARAMS displayParams = ByteArrayToStructure<DISPLAYPARAMS>(data, pin, offset);
91 VCSParamsDSP vcsPar = ByteArrayToStructure<VCSParamsDSP>(data, pin, offset);
92 handle.Free();
93
94 }
C++里的memcyp确实很好用,上段代码中,ByteArrayToStructure也能实现如memcyp一样的功能,先用GCHandle.Alloc选择Pinned生成CG不能回改的内存区域,和C++申请内存一样,然后根据偏移量offset,把对应的字节转成我们需要的数据.C++里的char和C#里的byte是一样的,都是一个字节,这里不要搞错了,也和C++一样,记的清除申请的内存空间。
本文内容不用于商业目的,如涉及知识产权问题,请权利人联系SPASVO小编(021-61079698-8054),我们将立即处理,马上删除。
相关推荐
编程常用的几种时间戳转换(java .net 数据库).Net中关于相等的问题Asp.net MVC如何对所有用户输入的字符串字段做Trim处理Asp.Net WebForm生命周期的详解.Net开发的两个小技巧asp.net 六大内置对象.Net基础体系和跨框架开发普及Linux使用Jexus托管Asp.Net Core应用程序asp.net登录验证码实现方法ASP.NET自带对象JSON字符串与实体类的转换从 .NET 和 Java 之争谈 IT 行业.Net高效开发之不可错过的实用工具ASP.NET MVC必须知道的那些事!.NET中使用无闪刷新控件时提示框不显示.net开发中要注意的事项Asp.net Core MVC中使用Session
更新发布
功能测试和接口测试的区别
2023/3/23 14:23:39如何写好测试用例文档
2023/3/22 16:17:39常用的选择回归测试的方式有哪些?
2022/6/14 16:14:27测试流程中需要重点把关几个过程?
2021/10/18 15:37:44性能测试的七种方法
2021/9/17 15:19:29全链路压测优化思路
2021/9/14 15:42:25性能测试流程浅谈
2021/5/28 17:25:47常见的APP性能测试指标
2021/5/8 17:01:11热门文章
常见的移动App Bug??崩溃的测试用例设计如何用Jmeter做压力测试QC使用说明APP压力测试入门教程移动app测试中的主要问题jenkins+testng+ant+webdriver持续集成测试使用JMeter进行HTTP负载测试Selenium 2.0 WebDriver 使用指南