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;
}
}
C# 进程间通信之二传递复杂数据类型(转)的更多相关文章
- Java 基础知识总结 (二、基本数据类型)
二.基本数据类型 java基本数据类型只能先声明后使用 boolean true/false char 16-bit unicode character byte 8-bit integer sho ...
- 二、C# 数据类型
C#语言的基本类型包括8种整数类型.2种用于科学计算的二进制浮点类型.1种用于金融计算的十 进制浮点类型.1种布尔类型以及1种字符类型. 2.1 基本数值类型 C#中的基本数据类型都有关键字和它们关联 ...
- WINCE下进程间通信(二)
WINCE下进程间通信(二) 接着前面的文章<WINCE下进程间通信(一)>,现在介绍进程间通信的另一种方法. 三.管道(消息队列) WINCE并不支持类似于PC机上匿名管道.命名管道的通 ...
- C#基础(二)--之数据类型
在第一章我们了解了C#的输入.输出语句后,我这一节主要是介绍C#的基础知识,本节的内容也是后续章节的基础,好的开端等于成功的一半.在你阅读完本章后,你就有足够的C#知识编写简单的程序了.但还不能使用继 ...
- 二、Python数据类型(一)
一.Python的基本输入与输出语句 (一)输出语句 print() 示例: print('你好,Python') print(4+5) a = 10 print(a) 输出的内容可以是字符串,变量, ...
- Redis系列(二):Redis的数据类型及命令操作
原文链接(转载请注明出处):Redis系列(二):Redis的数据类型及命令操作 Redis 中常用命令 Redis 官方的文档是英文版的,当然网上也有大量的中文翻译版,例如:Redis 命令参考.这 ...
- day02--Python基础二(基础数据类型)
一.数据与数据类型 1 什么是数据? x=10,10是我们要存储的数据 2 为何数据要分不同的类型 数据是用来表示状态的,不同的状态就应该用不同的类型的数据去表示 3 数据类型 数字(int) 字符串 ...
- python学习之路 二 :基本数据类型
本节重点 理解什么是变量? 掌握各种数据类型 理解可变类型和不可变类型 一.变量和常量 变量: 作用:存贮程序的中间结果在内存里,以备后边的程序调用 定义规范: 变量名只能是 字母.数字活下划线的任意 ...
- 二:Redis数据类型
一.nosql(非关系性数据库): mongoDB hbase redis nulch hive pig mahout zookeeper 二:redis 数据类型 1.存储string: 常用命令 ...
随机推荐
- JDK1.7 安装配置
JDK1.7 安装配置 1.下载jdk1.7安装包,下载地址为http://pan.baidu.com/s/1bnvWc5x: 2.安装jdk1.7,安装完成后可在安装目录下看到以下两个文件夹,如下图 ...
- LPTHW 结束了
基本上在学习了LPTHW的 类 继承 和 合成以后基本就结束. 后面几章都是根据web.py进行网页编程,以及自动化测试的.目前来看不太感兴趣. 稍后我可能找个实际项目进行锻炼下,比如 Crossin ...
- python webdriver 自动化测试练习 1-- 在线调查
__author__ = 'Mickey0s' # coding:utf8 from selenium import webdriver from selenium.webdriver.common. ...
- day27_反射
1.反射-概述(掌握) 反射就是在程序运行过程中,通过.class文件动态的获取类的信息(属性,构造,方法),并调用 注意:JAVA不是动态语言,因为动态语言强调在程序运行过程中不仅能获取并调用类里面 ...
- Java复习-oop
我们可理解“纯粹”的面向对象程序设计方法是什么样的:(1) 所有东西都是对象.可将对象想象成一种新型变量:它保存着数据,但可要求它对自身进行操作.理论上讲,可从要解决的问题身上提出所有概念性的组件,然 ...
- CLR via C# 3rd - 03 - Shared Assemblies and Strongly Named Assemblies
1. Weakly Named Assembly vs Strong Named Assembly Weakly named assemblies and strongly named ...
- 几种Position属性的用法
几种Position常见的属性就是一下几种: 1.static:默认值.没有定位,元素出现在正常的流中(忽略 top, bottom, left, right 或者 z-index 声明). 2.re ...
- web安全之sql注入的防御
自动把引号转义 1.防御sql注入的基本原则 任何时候不应该改变用户的输入 比如用户输入单引号,那输出也要是单引号. 几种基本的防 ...
- acm数学(转)
这个东西先放在这吧.做过的以后会用#号标示出来 1.burnside定理,polya计数法 这个大家可以看brudildi的<组合数学>,那本书的这一章写的很详细也很容易理解.最好能 ...
- CentOS6.5上Oracle11gR2静默安装
一.环境准备环境 操作系统:CentOS release 6.5 (Final) 内核版本:2.6.32-431.el6.x86_64 物理内存:2G(必须大于1G) swap分区:3G(必须大于3G ...