zoukankan      html  css  js  c++  java
  • C# 进程间通信之二传递复杂数据类型(转)

    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;

                         }

                  }

  • 相关阅读:
    linux系统中输入输出重定向 0<、<、1>、>、2>、1>>、>>、2>>、&>、>&、&>>、2>&1、<<
    linux系统统计某一行出现特定字符的次数
    linux系统中常用的通配符*、?、[ ]、[^xxx]、{}
    R语言strsplit函数用法
    linux系统统计某一字符出现的次数
    什么时候你需要一个虚构函数是虚的
    strcpy的返回值有什么用?
    boost.array 使用实例
    《DB 查询分析器》使用技巧之(七)
    《微型电脑应用》2011年第11期刊登出《万能数据库查询分析器中的事务管理在Oracle中的应用》
  • 原文地址:https://www.cnblogs.com/bile/p/5545898.html
Copyright © 2011-2022 走看看