c++与C# winform的消息通讯--(结构体与byte数组的使用)

摘要:
并且在消息发送中,很少介绍如何发送一个结构体,并且结构体里面有byte数组等如何进行处理。结果测试了一下,不行,提示内

转载:http://www.cnblogs.com/lizhaoduo/p/3870809.html

近期正在做一个蓝牙驱动的使用程序,其中有一块从c++发送数据到C#的部分,网上查了很多资料,大多都是介绍如何通过调用函数获取用户数据。并且在消息发送中,很少介绍如何发送一个结构体,并且结构体里面有

byte数组(硬件开发常用)等如何进行处理。

首先c++里面要建立一个dll文件:

复制代码
 1 BOOL APIENTRY DllMain( HMODULE hModule,    DWORD  ul_reason_for_call,LPVOID lpReserved)
 2 {
 3     switch (ul_reason_for_call)
 4     {
 5     case DLL_PROCESS_ATTACH:
 6     case DLL_THREAD_ATTACH:
 7     case DLL_THREAD_DETACH:
 8     case DLL_PROCESS_DETACH:
 9         break;
10     }
11     return TRUE;
12 }
13 
14 struct DevInfo//定义一个我自己的数据结构体
15 {
16     INT32 id;
17     char name[20];
18     char mac[25];
19     BYTE  data[100];
20 };
21 
22 extern "C" __declspec(dllexport) int sendTest(INT32 msg)//测试用的发布函数,这个int32参数一点作用都没有
23 {
24     DevInfo *pinfo=new DevInfo();
25     pinfo->id=999;
26     sprintf(pinfo->name,"myDevice");
27     sprintf(pinfo->mac,"19:4x:3a:4a");
28 
29     for (int i = 0; i < 100; i++)
30     {
31         pinfo->data[i]=(BYTE)(0x40+i);
32     }
33 
34     COPYDATASTRUCT cpd; /*给COPYDATASTRUCT结构赋值,COPYDATASTRUCT,这个也是系统自己定义的*/
35     cpd.dwData = 959;               //定义一个标示符(我这里没有用到)
36     cpd.cbData = sizeof(DevInfo);
37     cpd.lpData = pinfo;             //将指针的地址通过消息发送
38 
39     HWND handle2=::FindWindowA(NULL,(LPCSTR)"Form1");//获取窗口的句柄
40 
41     ::SendMessageA(handle2,WM_COPYDATA,(WPARAM)13,(LPARAM)&cpd);
42     
43     //这个地方必须要用sendMessageA,如果用post的话,则可能会出现数据还没有发送完
44     //系统就把定义的DevInfo 给清理掉了
45     
46     std::cout<<"发送数据消息"<<WM_COPYDATA<<std::endl;
47     delete pinfo;
48 
49     return 12;
50 }
复制代码

/*****************************************************************/
c#语言部分

复制代码
 1 namespace Test
 2 {
 3     public partial class Form1 : Form
 4     {
 5         public Form1()
 6         {
 7             InitializeComponent();
 8         }
 9         
10         private const int WM_COPYDATA = 0x004A;//自己定义一个消息是必须的了
11         
12         [DllImport("BlueTooth4.dll", EntryPoint = "sendTest", CallingConvention = CallingConvention.Cdecl)]
13         public static extern Int32 sendTest(int msg);//我们刚才执行的事件,这个是为了测试用才这样做的
14         
15         
16         [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
17         public struct COPYDATASTRUCT//定义数据传输的结构
18         {
19             public IntPtr dwData;
20             public int cbData;
21             public IntPtr lpData;
22         }
23 
24         //定义要传递的Struct
25        [StructLayout(LayoutKind.Sequential)]//如果发现处理的数据有乱码的话,则在此处加上 ,CharSet = CharSet.Ansi
26        struct dataInfo
27        {
28            public IntPtr id;
29           
30             [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
31            public string name;
32 
33            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 25)]
34            public string mac;
35            
36            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 100)]
37            public byte[] data;
38        }
39 
40         protected override void DefWndProc(ref Message m)//开始处理消息
41         {
42             switch (m.Msg)
43             {
44                 //接收CopyData消息,读取发送过来的数据
45                 case WM_COPYDATA:
46                  COPYDATASTRUCT copydata = new COPYDATASTRUCT();  
47                  COPYDATASTRUCT RecvData = (COPYDATASTRUCT)m.GetLParam(typeof(COPYDATASTRUCT));
48                  dataInfo h = (dataInfo)Marshal.PtrToStructure((IntPtr)RecvData.lpData, typeof(dataInfo));//这句和上面的一句就已经将数据进行转换了
49                    break;
50                 default:
51                     base.DefWndProc(ref m);
52                     break;
53             }
54 
55         }
56     }
57 }
复制代码

1、在这次处理的时候,在消息发送过来的数据遇到过是乱码的情况,可能是字符串的编码格式有问题( CharSet = CharSet.Ansi)也可能是长度定义的不够 托管与非托管之间创建了一个数据块,然后他将两个数据块进行对齐,然后将数据读取出来转变成我们想要的结构。

2、查过很多地方,好像在介绍c++post数据的时候,很少有介绍到用Byte数组的,而byte数组是在很多硬件设计(串口、usb)下使用比较多的 他的UnmanagedType应该是ByValArray

3、 dataInfo h = (dataInfo)Marshal.PtrToStructure((IntPtr)RecvData.lpData, typeof(dataInfo));//这句和上面的一句就已经将数据进行转换了 在这句上,我发现(IntPtr)RecvData.lpData,其实发送的就是pInfo的地址,当时想,我要是直接从dll发送给from不就可以了? 结果测试了一下,不行,提示内存错误。应该是托管代码与非托管代码之间为了数据交互增加的一个接口,一般不允许绕过! 估计有了这样的数据传输方式,一般硬件的数据传输基本上就ok了,以后完全可以用c++写驱动,写底层接口,用c#做界面开发了!!

免责声明:文章转载自《c++与C# winform的消息通讯--(结构体与byte数组的使用)》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇ASP.NET MVC 视图(二)SpringMVC2下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Winform 自定义文本框

using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading....

WPF中UI及时更新,如何在处理长时间工作时,保持界面的持续更新

 不管是在winform还是在WPF中,我们要做一个进度条,用在一个大循环或者一个耗时的处理中,首先想到的就是多线程。否则进度条会出现假死现象,进度条不会更新。做多线程是比较麻烦的,如果只是简单的更新UI,可以用Systems.DoEvents。 在winform中,使用PeekMessage处理完消息队列,使UI有机会更新。在WPF中,可以在Dispat...

Winform记录日志信息(Serilog.AspNetCore)

1.注意:必须使用.net Core以上版本的winform才能使用,.Net4.X系列无法使用,建议使用.Net 5创建。 2. 添加ASP.NET Core、Serilog支持   2.1 Nuget 安装相关Nuget包   Microsoft.Extensions.Hosting要指定版本,不能高于2.2.0: Install-Package...

关于C# winform唤起本地已安装应用程序(测试win10,win7可用)

想要唤起本地已安装应用程序,我想到的有三种可行的方法:   第一种就是打开本地的快捷方式(有的应用可能没有快捷方式,但这种方法效率最高,可配合其他方法使用),快捷方式分为本地桌面快捷方式和开始菜单中的快捷方式两种。   下面讲找出快捷方式路径的方法:     本地桌面快捷方式:用户可能更改过默认的桌面路径,此时以前添加的快捷方式还在默认的c盘下路径,之后创...

WinForm GDI+自定义控件总结(一)

前言   由于项目的原因好久没写博客了,也正是项目的原因开始系统的学习WinForm,从而接触到自定义控件的开发。自定义控件的开发有一定的难度,对开发者要求比较高,需要了解Windows运行的机制,熟悉win32Api和GDI+。下面是我收集的一些资料,挺不错的。 资料 .NET组件编程http://www.cnblogs.com/mapserver/ca...

winform(三)——更换主窗体例子

做一个登录窗口,登录成功时关闭form1,展示from2界面 1.主界面Login namespace WindowsFormsApplication1 { public partial class Login : Form { public string username;//定义一个变量给子窗体传值...