zoukankan      html  css  js  c++  java
  • 从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;
    
                         }
    
                  }

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

  • 相关阅读:
    MVC路由配置例
    js制作烟花效果
    限制帐号同时两处以上登录-ASP.NET
    地图按范围查找-经纬度计算
    多种JSON格式及遍历方式
    .net错误日志记录(log4)
    .net WebServer示例及调用(接口WSDL动态调用 JAVA)
    关于大型网站技术演进的思考
    优化网站加载速度的14个技巧
    大型网站架构改进历程
  • 原文地址:https://www.cnblogs.com/DoNetCShap/p/2564462.html
Copyright © 2011-2022 走看看