从C#下使用WM_COPYDATA传输数据说到Marshal的应用

       笔者曾在一个项目的实施过程中,需要使用 WM_COPYDATA 在本地机器的两个进程间传输数据。在 C++ 中实现非常简单,但在 C# 中实现时却出现了麻烦。由于没有指针,使用 COPYDATASTRUCT 结构传递数据时,无法正确传递 lpData 。从网上搜寻文档,找到一个例子,是将 COPYDATASTRUCT 结构的 lpData 声明为 string 。这样虽然能传递字符串,但不能传递随意的二进制数据。

       偶然地,我查阅 MSDN 帮助时,发现了 Marshal 类。该类概述描述道:提供了一个方法集,这些方法用于分配非托管内存、复制非托管内存块、将托管类型转换为非托管类型,此外还提供了在与非托管代码交互时使用的其他杂项方法 。这时,我豁然开朗,觉得找到了一个托管代码与非托管代码交互的桥梁。

       于是我声明 COPYDATASTRUCT 如下:

       [StructLayout(LayoutKind.Sequential)]

              public struct COPYDATASTRUCT

              {

                     public IntPtr dwData;

                     public int cbData;

                     public IntPtr lpData;

              }

       在发送数据时,我使用 Marshal 类分配一块全局内存,并将数据拷入这块内存,然后发送消息:

       COPYDATASTRUCT cds;

              cds.dwData = (IntPtr)flag;

              cds.cbData = data.Length;

              cds.lpData = Marshal.AllocHGlobal(data.Length);

              Marshal.Copy(data,0,cds.lpData,data.Length);

              SendMessage(WINDOW_HANDLER,WM_COPYDATA,0,ref cds);

在接收数据时,我使用 Marshal 类将数据从这块全局内存拷出,然后处理消息:

COPYDATASTRUCT cds = new COPYDATASTRUCT();

     Type mytype = cds.GetType();

              cds = (COPYDATASTRUCT)m.GetLParam(mytype);

              uint flag = (uint )(cds.dwData);

              byte [] bt = new byte [cds.cbData];

       Marshal.Copy(cds.lpData,bt,0,bt.Length);

详细源码如下:

/// <summary>

       /// Windows 的 COPYDATA 消息封装类。

       /// </summary>

       public class Messager : System.Windows.Forms.Form

       {

              /// <summary>

              /// 必需的设计器变量。

              /// </summary>

              private System.ComponentModel.Container components = null ;

 

              // 消息标识

              private const int WM_COPYDATA = 0x004A;

              // 消息数据类型 (typeFlag 以上二进制, typeFlag 以下字符 )

              private const uint typeFlag = 0x8000;

              /// <summary>

              /// 重载 CopyDataStruct

              /// </summary>

              [StructLayout(LayoutKind.Sequential)]

              public struct COPYDATASTRUCT

              {

                     public IntPtr dwData;

                     public int cbData;

                     public IntPtr lpData;

              }

              //

              [DllImport("User32.dll",EntryPoint="SendMessage")]

              private static extern int SendMessage(

                     int hWnd,                                  // handle to destination window

                     int Msg,                              // message

                     int wParam,                               // first message parameter

                     ref COPYDATASTRUCT lParam    // second message parameter

                     );

              //

              [DllImport("User32.dll",EntryPoint="FindWindow")]

              private static extern int FindWindow(string lpClassName,string lpWindowName);

 

              // 接收到数据委托与事件定义

              public delegate void ReceiveStringEvent(object sender,uint flag,string str);        

              public delegate void ReceiveBytesEvent(object sender,uint flag,byte [] bt);

              public event ReceiveStringEvent OnReceiveString;

              public event ReceiveBytesEvent OnReceiveBytes;

              // 发送数据委托与事件定义

              public delegate void SendStringEvent(object sender,uint flag,string str);            

              public delegate void SendBytesEvent(object sender,uint flag,byte [] bt);

              public event SendStringEvent OnSendString;

              public event SendBytesEvent OnSendBytes;

              //

              public Messager()

              {

                     //

                     // Windows 窗体设计器支持所必需的

                     //

                     InitializeComponent();

                     //

                     // TODO: 在 InitializeComponent 调用后添加任何构造函数代码

                     //

              }

 

              /// <summary>

              /// 清理所有正在使用的资源。

              /// </summary>

              protected override void Dispose( bool disposing )

              {

                     if ( disposing )

                     {

                            if (components != null )

                            {

                                   components.Dispose();

                            }

                     }

                     base .Dispose( disposing );

              }

 

              #region Windows 窗体设计器生成的代码

              /// <summary>

              /// 设计器支持所需的方法 - 不要使用代码编辑器修改

              /// 此方法的内容。

              /// </summary>

              private void InitializeComponent()

              {

                     //

                     // Messager

                     //

                     this .AutoScaleBaseSize = new System.Drawing.Size(6, 14);

                     this .ClientSize = new System.Drawing.Size(200, 14);

                     this .Name = "Messager";

                     this .ShowInTaskbar = false ;

                     this .Text = "Demo_Emluator";

                     this .WindowState = System.Windows.Forms.FormWindowState.Minimized;

 

              }

              #endregion           

              /// <summary>

              /// 重载窗口消息处理函数

              /// </summary>

              /// <param name="m"></param>

              protected override void DefWndProc(ref System.Windows.Forms.Message m)

              {

                     switch (m.Msg)

                     {

                            // 接收 CopyData 消息,读取发送过来的数据

                            case WM_COPYDATA:

                                   COPYDATASTRUCT cds = new COPYDATASTRUCT();

                           Type mytype = cds.GetType();

                                   cds = (COPYDATASTRUCT)m.GetLParam(mytype);

                                   uint flag = (uint )(cds.dwData);

                                   byte [] bt = new byte [cds.cbData];

                                   Marshal.Copy(cds.lpData,bt,0,bt.Length);

                                   if (flag <= typeFlag)

                                   {

                                          if (OnReceiveString != null )

                                          {

                                                 OnReceiveString(this ,flag,System.Text.Encoding.Default.GetString(bt));

                                          }

                                   }

                                   else

                                   {

                                          if (OnReceiveBytes != null )

                                          {

                                                 OnReceiveBytes(this ,flag,bt);

                                          }

                                   }

                                   break ;

                            default :

                                   base .DefWndProc(ref m);

                                   break ;

                     }

              }

              /// <summary>

              /// 发送字符串格式数据

              /// </summary>

              /// <param name="destWindow"> 目标窗口标题 </param>

              /// <param name="flag"> 数据标志 </param>

              /// <param name="str"> 数据 </param>

              /// <returns></returns>

              public bool SendString(string destWindow,uint flag,string str)

              {

                     if (flag > typeFlag)

                     {

                            MessageBox.Show(" 要发送的数据不是字符格式 ");

                            return false ;

                     }

                     int WINDOW_HANDLER = FindWindow(null ,@destWindow);

                     if (WINDOW_HANDLER == 0) return false ;

                     try

                     {

                            byte [] sarr = System.Text.Encoding.Default.GetBytes(str);

                            COPYDATASTRUCT cds;

                            cds.dwData = (IntPtr)flag;

                            cds.cbData = sarr.Length;

                            cds.lpData = Marshal.AllocHGlobal(sarr.Length);

                            Marshal.Copy(sarr,0,cds.lpData,sarr.Length);

                            SendMessage(WINDOW_HANDLER,WM_COPYDATA,0,ref cds);

                            if (OnSendString != null )

                            {

                                   OnSendString(this ,flag,str);

                            }

                            return true ;

                     }

                     catch (Exception e)

                     {

                            MessageBox.Show(e.Message);

                            return false ;

                     }

              }

              /// <summary>

              /// 发送二进制格式数据

              /// </summary>

              /// <param name="destWindow"> 目标窗口 </param>

              /// <param name="flag"> 数据标志 </param>

              /// <param name="data"> 数据 </param>

              /// <returns></returns>

              public bool SendBytes(string destWindow,uint flag,byte [] data)

              {

                     if (flag <= typeFlag)

                     {

                            MessageBox.Show(" 要发送的数据不是二进制格式 ");

                            return false ;

                     }

                     int WINDOW_HANDLER = FindWindow(null ,@destWindow);

                     if (WINDOW_HANDLER == 0) return false ;

                     try

                     {

                            COPYDATASTRUCT cds;

                            cds.dwData = (IntPtr)flag;

                            cds.cbData = data.Length;

                            cds.lpData = Marshal.AllocHGlobal(data.Length);

                            Marshal.Copy(data,0,cds.lpData,data.Length);

                            SendMessage(WINDOW_HANDLER,WM_COPYDATA,0,ref cds);

                            if (OnSendBytes != null )

                            {

                                   OnSendBytes(this ,flag,data);

                            }

                            return true ;

                     }

                     catch (Exception e)

                     {

                            MessageBox.Show(e.Message);

                            return false ;

                     }

              }

       通过测试使用,毫无问题。现贴出来,供后来者参考。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值