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;

}

}

C# 进程间通信之二传递复杂数据类型(转)的更多相关文章

  1. Java 基础知识总结 (二、基本数据类型)

    二.基本数据类型 java基本数据类型只能先声明后使用 boolean  true/false char 16-bit unicode character byte 8-bit integer sho ...

  2. 二、C# 数据类型

    C#语言的基本类型包括8种整数类型.2种用于科学计算的二进制浮点类型.1种用于金融计算的十 进制浮点类型.1种布尔类型以及1种字符类型. 2.1 基本数值类型 C#中的基本数据类型都有关键字和它们关联 ...

  3. WINCE下进程间通信(二)

    WINCE下进程间通信(二) 接着前面的文章<WINCE下进程间通信(一)>,现在介绍进程间通信的另一种方法. 三.管道(消息队列) WINCE并不支持类似于PC机上匿名管道.命名管道的通 ...

  4. C#基础(二)--之数据类型

    在第一章我们了解了C#的输入.输出语句后,我这一节主要是介绍C#的基础知识,本节的内容也是后续章节的基础,好的开端等于成功的一半.在你阅读完本章后,你就有足够的C#知识编写简单的程序了.但还不能使用继 ...

  5. 二、Python数据类型(一)

    一.Python的基本输入与输出语句 (一)输出语句 print() 示例: print('你好,Python') print(4+5) a = 10 print(a) 输出的内容可以是字符串,变量, ...

  6. Redis系列(二):Redis的数据类型及命令操作

    原文链接(转载请注明出处):Redis系列(二):Redis的数据类型及命令操作 Redis 中常用命令 Redis 官方的文档是英文版的,当然网上也有大量的中文翻译版,例如:Redis 命令参考.这 ...

  7. day02--Python基础二(基础数据类型)

    一.数据与数据类型 1 什么是数据? x=10,10是我们要存储的数据 2 为何数据要分不同的类型 数据是用来表示状态的,不同的状态就应该用不同的类型的数据去表示 3 数据类型 数字(int) 字符串 ...

  8. python学习之路 二 :基本数据类型

    本节重点 理解什么是变量? 掌握各种数据类型 理解可变类型和不可变类型 一.变量和常量 变量: 作用:存贮程序的中间结果在内存里,以备后边的程序调用 定义规范: 变量名只能是 字母.数字活下划线的任意 ...

  9. 二:Redis数据类型

    一.nosql(非关系性数据库): mongoDB hbase redis nulch hive pig mahout zookeeper 二:redis 数据类型 1.存储string: 常用命令 ...

随机推荐

  1. 百川sdk----自己的WebViewClient不被执行

    我在百川sdk的旺旺群中,追问这个问题N多次,一直没有人答复,哎,凡事都要靠自己..... 1.先查看下百川sdk中,是怎么处理咱们传递过去的 WebViewClient public class l ...

  2. 国内如何使用gem?

    答案很简单,使用淘宝镜像! https://ruby.taobao.org/ 造福人类啊! 设置方法: $ gem sources --add https://ruby.taobao.org/ --r ...

  3. DNS记录类型介绍(A记录、MX记录、NS记录等)

    DNS A记录 NS记录 MX记录 CNAME记录 TXT记录 TTL值 PTR值 建站名词解释:DNS A记录 NS记录 MX记录 CNAME记录 TXT记录 TTL值 PTR值 泛域名 泛解析 域 ...

  4. Eclipse vs. IDEA快捷键对比大全

    原文链接: http://blog.csdn.net/dc_726 花了一天时间熟悉IDEA的各种操作,将各种快捷键都试了一下,感觉很是不错!于是就整理了一下我经常用的一些Eclipse快捷键与IDE ...

  5. VIM-Sed常用的一些记录。。。逐渐学习。。

    :[range]co[py] {address} :t :[range]m[ove] {address] 例如 :1,3t10  1-3行复制到10行后.用m就是移动了. :sort / /   // ...

  6. 设为首页 添加到收藏夹 (share)

    设为首页,添加到收藏夹 分享自:http://my.oschina.net/lyx2012/blog/60036 设为首页 和 收藏本站js代码 兼容IE,chrome,ff <script t ...

  7. Weblogic新增域(可以配置新端口)

    操作系统 :Linux version 2.6.32-504.el6.x86_64 Weblogic Server :11g 一.Weblogic新增域(可以配置新端口) 以weblogic用户登录 ...

  8. (转)COM组件里的AddRef()

    D3D是 COM组件,它在服务进程中运行,而不在当前的客户进程中.在DX组件运行过程中,要创建一系列接口对象,如CreateDevice()返回接口指针,这些接口及其占用内存什么时候释放,要通过“引用 ...

  9. junit单元测试(keeps the bar green to keeps the code clean)

    error是程序错误,failure是测试错误. junit概要: JUnit是由 Erich Gamma (设计模式的创始人)和 Kent Beck (敏捷开发的创始人之一)编写的一个回归测试框架( ...

  10. web安全之ssrf

    ssrf(服务器端请求伪造)原理: 攻击者构造形成由服务端发起请求的一个漏洞.把服务端当作跳板来攻击其他服务,SSRF的攻击目标一般是外网无法访问到的内网 当服务端提供了从其他服务器获取数据的功能(如 ...