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


    近期正在做一个蓝牙驱动的使用程序,其中有一块从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#做界面开发了!!

  • 相关阅读:
    Linux基础命令—clear
    Linux基础命令—mv
    Linux基础命令—rm
    Linux基础命令—cp
    Linux基础命令—touch
    Linux基础命令—tree
    C#获取设备话筒主峰值(实时音频输出分贝量)
    C# 获取基类或者接口的所有继承类方法
    RegisterAttached 两种绑定方式
    RijndaelManaged 加密
  • 原文地址:https://www.cnblogs.com/lizhaoduo/p/3870809.html
Copyright © 2020-2023  润新知