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

 

    利用WM_COPYDATA可以轻松实现两个进程间的通信,但是一般都是传string数据,今天看到CSDN上有人问如何传Struct。下面是我的解决方法。

[StructLayout(LayoutKind.Sequential)]
            
public  struct  COPYDATASTRUCT
        
{
            
public int dwData;
            
public int cbData;
            
public int lpData;
        }

        [DllImport(
" user32 " , EntryPoint  =  " SendMessageA " )]
        
public  static  extern  int  SendMessage( int  Hwnd,  int  wMsg,  int  wParam,  ref  COPYDATASTRUCT lParam);
        
const  int  WM_COPYDATA  =  0x004A ;

        
// 定义要传递的Struct
        [StructLayout(LayoutKind.Sequential)]
        
struct  WholeInfo
        
{
            
//SizeConst指定字符串很重要,后面要用到
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 10)]
            
public string cPath;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst 
= 10)]
            
public string lPath;
            
public bool status;
        }



// 发送方代码

            WholeInfo h
= new  WholeInfo();
            h.lPath
= " lPath " ;
            h.cPath 
= " cPath " ;
            h.status
= true ;
            
int  size  =  Marshal.SizeOf( typeof (WholeInfo ));
            
byte [] Bytes  =  new  byte [size];
            
// 根据定义的尺寸分配内存块
            GCHandle GC  =  GCHandle.Alloc(Bytes, GCHandleType.Pinned);
            IntPtr ptr1 
=  GC.AddrOfPinnedObject();
            
// 获得Struct对应的IntPtr
            Marshal.StructureToPtr(h, ptr1, false  );            
            SendData.lpData 
=  ptr1.ToInt32();
            SendData.cbData 
= size;           

            
int  intHWnd   =  FindWindow( null , @" 接收方 " );
            
if  (intHWnd  >  0 )
            
{
                SendMessage(intHWnd ,  WM_COPYDATA, 
0,ref (SendData));
            }


// 接收方代码

        
// 处理消息
         protected  override  void  DefWndProc( ref  System.Windows.Forms.Message m)
        
{
            
switch(m.Msg)
            
{
                
case WM_COPYDATA:
                    COPYDATASTRUCT RecvData 
= (COPYDATASTRUCT)m.GetLParam(typeof(COPYDATASTRUCT));
                     WholeInfo h 
= (WholeInfo)Marshal.PtrToStructure((IntPtr)RecvData.lpData, typeof(WholeInfo));
                    
this.textBox1.Text = h.cPath ;
                    
                    
break;
                
default:
                    
base.DefWndProc(ref m);
                    
break;

            }


        }


关键的代码就是
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 10)]

这样C#才能分配正确的内存位置,但是要记住一个汉字占2位

 

 

2:从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;

                     }

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

转载于:https://www.cnblogs.com/vhtt/archive/2012/11/01/2750451.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值