您的位置:首页 > 编程语言 > C#

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

2009-12-02 17:46 501 查看
笔者曾在一个项目的实施过程中,需要使用
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
;

}

}

通过测试使用,毫无问题。现贴出来,供后来者参考。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐