设置系统时间,进程间通信之二传递复杂数据类型
分类:高并发

中国最大的WEB开发资源网站及技术社区,

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

using System ;

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Runtime.InteropServices;

简介:

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

using System.Drawing ;

namespace WindowsApplication1
{
[StructLayout(LayoutKind.Sequential)]
public struct SystemTime
{
public ushort wYear;
public ushort wMonth;
public ushort wDayOfWeek;
public ushort wDay;
public ushort wHour;
public ushort wMinute;
public ushort wSecond;
public ushort wMiliseconds;
}

本文着重讲述了如果用WM_COPYDATA消息来实现两个进程之间传递数据.

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

using System.Collections ;

public class Win32
{
[DllImport("Kernel32.dll")]
public static extern bool SetSystemTime( ref SystemTime sysTime );
[DllImport("Kernel32.dll")]
public static extern void GetSystemTime(ref SystemTime sysTime);
}

进程之间通讯的几种方法:

       于是我声明COPYDATASTRUCT如下:

using System.ComponentModel ;

///
/// Form1 的摘要说明。
///
public class Form1 : System.Windows.Forms.Form
{
private System.Windows.Forms.Button button1;
private System.Windows.Forms.TextBox textBox1;
private System.Windows.Forms.TextBox textBox2;
///
/// 必需的设计器变量。
///
private System.ComponentModel.Container components = null;

在Windows程序中,各个进程之间常常需要交换数据,进行数据通讯。常用的方法有

       [StructLayout(LayoutKind.Sequential)]

using System.Windows.Forms ;

public Form1()
{
//
// Windows 窗体设计器支持所必需的
//
InitializeComponent();

  使用内存映射文件
  通过共享内存DLL共享内存
  使用SendMessage向另一进程发送WM_COPYDATA消息

              public struct COPYDATASTRUCT

using System.Data ;

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

比起前两种的复杂实现来,WM_COPYDATA消息无疑是一种经济实惠的一中方法.

              {

using System.Runtime.InteropServices ;

///
/// 清理所有正在使用的资源。
///
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}

WM_COPYDATA消息的主要目的是允许在进程间传递只读数据。Windows在通过WM_COPYDATA消息传递期间,不提供继承同步方式。SDK文档推荐用户使用SendMessage函数,接受方在数据拷贝完成前不返回,这样发送方就不可能删除和修改数据:

                     public IntPtr dwData;

using System.Text ;

#region Windows 窗体设计器生成的代码
///
/// 设计器支持所需的方法 - 不要使用代码编辑器修改
/// 此方法的内容。
///
private void InitializeComponent()
{
this.button1 = new System.Windows.Forms.Button();
this.textBox1 = new System.Windows.Forms.TextBox();
this.textBox2 = new System.Windows.Forms.TextBox();
this.SuspendLayout();
//
// button1
//
this.button1.Location = new System.Drawing.Point(188, 174);
this.button1.Name = "button1";
this.button1.TabIndex = 0;
this.button1.Text = "button1";
this.button1.Click += new System.EventHandler(this.button1_Click);
//
// textBox1
//
this.textBox1.Location = new System.Drawing.Point(56, 12);
this.textBox1.Name = "textBox1";
this.textBox1.Size = new System.Drawing.Size(510, 21);
this.textBox1.TabIndex = 1;
this.textBox1.Text = "textBox1";
//
// textBox2
//
this.textBox2.Location = new System.Drawing.Point(58, 50);
this.textBox2.Name = "textBox2";
this.textBox2.Size = new System.Drawing.Size(506, 21);
this.textBox2.TabIndex = 2;
this.textBox2.Text = "textBox2";
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(6, 14);
this.ClientSize = new System.Drawing.Size(602, 273);
this.Controls.Add(this.textBox2);
this.Controls.Add(this.textBox1);
this.Controls.Add(this.button1);
this.Name = "Form1";
this.Text = "Form1";
this.ResumeLayout(false);

这个函数的原型及其要用到的结构如下:

                     public int cbData;

namespace C_操作INI文件__写操作

}
#endregion

SendMessage(hwnd,WM_COPYDATA,wParam,lParam);
其中,WM_COPYDATA对应的十六进制数为0x004A

                     public IntPtr lpData;

{

///
/// 应用程序的主入口点。
///
[STAThread]
static void Main()
{
Application.Run(new Form1());
}

wParam设置为包含数据的窗口的句柄。lParam指向一个COPYDATASTRUCT的结构:
typedef struct tagCOPYDATASTRUCT{
    DWORD dwData;//用户定义数据
    DWORD cbData;//数据大小
    PVOID lpData;//指向数据的指针
}COPYDATASTRUCT;
该结构用来定义用户数据。

              }

public class Form1 : System.Windows.Forms.Form

private void button1_Click(object sender, System.EventArgs e)
{
textBox1.Text = DateTime.Now.ToLongDateString() + DateTime.Now.ToLongTimeString();
SystemTime sysTime = new SystemTime();

具体过程如下:

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

{

sysTime.wYear = Convert.ToUInt16(DateTime.Now.Year);
sysTime.wMonth = Convert.ToUInt16(DateTime.Now.Month);
//处置北京时间
int nBeijingHour = DateTime.Now.Hour - 8;
if (nBeijingHour <= 0)
{
nBeijingHour += 24;
sysTime.wDay= Convert.ToUInt16(DateTime.Now.Day - 1);
sysTime.wDayOfWeek = Convert.ToUInt16(DateTime.Now.DayOfWeek - 1);
}
else
{
sysTime.wDay= Convert.ToUInt16(DateTime.Now.Day);
sysTime.wDayOfWeek = Convert.ToUInt16(DateTime.Now.DayOfWeek);
}
sysTime.wHour = Convert.ToUInt16(nBeijingHour);
sysTime.wMinute = Convert.ToUInt16(DateTime.Now.Minute);
sysTime.wSecond = Convert.ToUInt16(DateTime.Now.Second);
sysTime.wMiliseconds = Convert.ToUInt16(DateTime.Now.Millisecond);

首先,在发送方,用FindWindow找到接受方的句柄,然后向接受方发送WM_COPYDATA消息.

       COPYDATASTRUCT cds;

private System.Windows.Forms.Button button1 ;

Win32.SetSystemTime(ref sysTime);
textBox2.Text = DateTime.Now.ToLongDateString() + DateTime.Now.ToLongTimeString();
}

接受方在DefWndProc事件中,来处理这条消息.由于中文编码是两个字节,所以传递中文时候字节长度要搞清楚.

              cds.dwData = (IntPtr)flag;

private System.Windows.Forms.TextBox textBox1 ;

}
}

代码中有适量的解释,大家请自己看吧.

              cds.cbData = data.Length;

private System.Windows.Forms.Button button2 ;

具体代码如下:
//---------------------------------------------------
//发送方:
//---------------------------------------------------

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

private System.Windows.Forms.TextBox textBox2 ;

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Runtime.InteropServices;

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

private System.Windows.Forms.TextBox textBox3 ;

namespace WindowsFormGetMsg
{
 public class Form1 : System.Windows.Forms.Form
 {
  private System.Windows.Forms.TextBox textBox1;
  private System.ComponentModel.Container components = null;
  const int WM_COPYDATA = 0x004A;

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

private System.Windows.Forms.TextBox textBox4 ;

  public Form1()
  {
   InitializeComponent();
  }

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

private System.Windows.Forms.Label label1 ;

  protected override void Dispose( bool disposing )
  {
   if( disposing )
   {
    if (components != null)
    {
     components.Dispose();
    }
   }
   base.Dispose( disposing );
  }

COPYDATASTRUCT cds = new COPYDATASTRUCT();

private System.Windows.Forms.Label label2 ;

  #region Windows Form Designer generated code
  private void InitializeComponent()
  {
   this.textBox1 = new System.Windows.Forms.TextBox();
   this.SuspendLayout();
   //
   // textBox1
   //
   this.textBox1.Location = new System.Drawing.Point

    Type mytype = cds.GetType();

private System.Windows.Forms.Label label3 ;

(176, 32);
   this.textBox1.Name = "textBox1";
   this.textBox1.Size = new System.Drawing.Size(160,

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

private System.Windows.Forms.Button button3 ;

21);
   this.textBox1.TabIndex = 0;
   this.textBox1.Text = "textBox1";
   //
   // Form1
   //
   this.AutoScaleBaseSize = new System.Drawing.Size(6,

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

private System.Windows.Forms.OpenFileDialog openFileDialog1 ;

14);
   this.ClientSize = new System.Drawing.Size(432, 266);
   this.Controls.AddRange(new

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

private System.ComponentModel.Container components = null ;

System.Windows.Forms.Control[] {           

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

public Form1 ( )

         

详细源码如下:

{

this.textBox1});
   this.Name = "Form1";
   this.Text = "接收方";
   this.ResumeLayout(false);

/// <summary>

InitializeComponent ( ) ;

  }
  #endregion

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

}

  [STAThread]
  static void Main()
  {
   Application.Run(new Form1());
  }

       /// </summary>

protected override void Dispose ( bool disposing )

  protected override void DefWndProc(ref

       public class Messager : System.Windows.Forms.Form

{

System.Windows.Forms.Message m)
  {
   switch(m.Msg)
   {
     //接收自定义消息 USER,并显示其参数
    case WM_COPYDATA:
     COPYDATASTRUCT mystr = new

       {

if ( disposing )

COPYDATASTRUCT();
       Type mytype = mystr.GetType();

              /// <summary>

{

       mystr =(COPYDATASTRUCT)m.GetLParam(mytype);
     this.textBox1.Text  =mystr.lpData;

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

if ( components != null )

     break;
    default:
     base.DefWndProc(ref m);
     break;

              /// </summary>

{

   }

              private System.ComponentModel.Container components = null;

components.Dispose ( ) ;

  }

 

}

 }
 [StructLayout(LayoutKind.Sequential)]
 public struct COPYDATASTRUCT
 {
  public IntPtr dwData;
  public int cbData;
  [MarshalAs(UnmanagedType.LPStr)] public string lpData;
 }
}

              //消息标识

}

//---------------------------------------------------
//接受方
//---------------------------------------------------
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Runtime.InteropServices;

              private const int WM_COPYDATA = 0x004A;

base.Dispose ( disposing ) ;

namespace WindowsFormGetMsg
{
 public class Form1 : System.Windows.Forms.Form
 {
  private System.Windows.Forms.TextBox textBox1;
  private System.ComponentModel.Container components = null;
  const int WM_COPYDATA = 0x004A;

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

}

  public Form1()
  {
   InitializeComponent();
  }

              private const uint typeFlag = 0x8000;

[ DllImport ( "kernel32" ) ]

  protected override void Dispose( bool disposing )
  {
   if( disposing )
   {
    if (components != null)
    {
     components.Dispose();
    }
   }
   base.Dispose( disposing );
  }

              /// <summary>

private static extern long WritePrivateProfileString ( string

  #region Windows Form Designer generated code
  private void InitializeComponent()
  {
   this.textBox1 = new System.Windows.Forms.TextBox();
   this.SuspendLayout();
   //
   // textBox1
   //
   this.textBox1.Location = new System.Drawing.Point

              /// 重载CopyDataStruct

section ,

(176, 32);
   this.textBox1.Name = "textBox1";
   this.textBox1.Size = new System.Drawing.Size(160,

              /// </summary>

string key , string val , string filePath ) ;

21);
   this.textBox1.TabIndex = 0;
   this.textBox1.Text = "textBox1";
   //
   // Form1
   //
   this.AutoScaleBaseSize = new System.Drawing.Size(6,

              [StructLayout(LayoutKind.Sequential)]

[ DllImport ( "kernel32" ) ]

14);
   this.ClientSize = new System.Drawing.Size(432, 266);
   this.Controls.AddRange(new

              public struct COPYDATASTRUCT

private static extern int GetPrivateProfileString ( string section ,

System.Windows.Forms.Control[] {           

              {

string key , string def , StringBuilder retVal ,

         

                     public IntPtr dwData;

int size , string filePath ) ;

this.textBox1});
   this.Name = "Form1";
   this.Text = "接收方";
   this.ResumeLayout(false);

                     public int cbData;

private void InitializeComponent ( )

  }
  #endregion

                     public IntPtr lpData;

{

  [STAThread]
  static void Main()
  {
   Application.Run(new Form1());
  }

              }

this.button1 = new System.Windows.Forms.Button ( ) ;

  protected override void DefWndProc(ref

              //

this.textBox1 = new System.Windows.Forms.TextBox ( ) ;

System.Windows.Forms.Message m)
  {
   switch(m.Msg)
   {
     //接收自定义消息 USER,并显示其参数
    case WM_COPYDATA:
     COPYDATASTRUCT mystr = new

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

this.button2 = new System.Windows.Forms.Button ( ) ;

COPYDATASTRUCT();
       Type mytype = mystr.GetType();

              private static extern int SendMessage(

this.textBox2 = new System.Windows.Forms.TextBox ( ) ;

       mystr =(COPYDATASTRUCT)m.GetLParam(mytype);
     this.textBox1.Text  =mystr.lpData;

                     int hWnd,                                  // handle to destination window

this.textBox3 = new System.Windows.Forms.TextBox ( ) ;

     break;
    default:
     base.DefWndProc(ref m);
     break;

                     int Msg,                              // message

this.textBox4 = new System.Windows.Forms.TextBox ( ) ;

   }

                     int wParam,                               // first message parameter

this.label1 = new System.Windows.Forms.Label ( ) ;

  }

                     ref COPYDATASTRUCT lParam    // second message parameter

this.label2 = new System.Windows.Forms.Label ( ) ;

 }
 [StructLayout(LayoutKind.Sequential)]
 public struct COPYDATASTRUCT
 {
  public IntPtr dwData;
  public int cbData;
  [MarshalAs(UnmanagedType.LPStr)] public string lpData;
 }
}

                     );

this.label3 = new System.Windows.Forms.Label ( ) ;

<> <>

              //

this.button3 = new System.Windows.Forms.Button ( ) ;

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

this.openFileDialog1 = new

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

System.Windows.Forms.OpenFileDialog ( ) ;

 

this.SuspendLayout ( ) ;

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

this.button1.FlatStyle = System.Windows.Forms.FlatStyle.Flat ;

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

this.button1.Location = new System.Drawing.Point ( 238 , 20 ) ;

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

this.button1.Name = "button1" ;

              public event ReceiveStringEvent OnReceiveString;

this.button1.Size = new System.Drawing.Size ( 100 , 32 ) ;

              public event ReceiveBytesEvent OnReceiveBytes;

this.button1.TabIndex = 0 ;

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

this.button1.Text = "选择INI文件" ;

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

this.button1.Click += new System.EventHandler ( this.button1_Click ) ;

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

this.textBox1.Location = new System.Drawing.Point ( 58 , 22 ) ;

              public event SendStringEvent OnSendString;

this.textBox1.Name = "textBox1" ;

              public event SendBytesEvent OnSendBytes;

this.textBox1.Size = new System.Drawing.Size ( 162 , 21 ) ;

              //

this.textBox1.TabIndex = 1 ;

              public Messager()

this.textBox1.Text = "" ;

              {

this.button2.FlatStyle = System.Windows.Forms.FlatStyle.Flat ;

                     //

this.button2.Location = new System.Drawing.Point ( 86 , 168 ) ;

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

this.button2.Name = "button2" ;

                     //

this.button2.Size = new System.Drawing.Size ( 98 , 30 ) ;

                     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;

                     }

              }

 

本文由10bet手机官网发布于高并发,转载请注明出处:设置系统时间,进程间通信之二传递复杂数据类型

上一篇:装饰模式,PHP设计模式之责任链模式的深入解析_php技巧_脚本之家 下一篇:没有了
猜你喜欢
热门排行
精彩图文