从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
;
}
}
通过测试使用,毫无问题。现贴出来,供后来者参考。
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#下使用WM_COPYDATA传输数据说到Marshal的应用
- 从C#下使用WM_COPYDATA传输数据说到Marshal的应用
- 从C#下使用WM_COPYDATA传输数据说到Marshal的应用
- 使用WM_COPYDATA消息在C++和C#程序之间互传数据
- 利用 WM_COPYDATA 消息 在 C# 和 传统C++应用之间传递数据时,64位平台的问题
- VC++ 中WM_COPYDATA 怎么样应用来实现两个进程间的数据传输
- Oracle 远程访问配置 在 Windows Forms 和 WPF 应用中使用 FontAwesome 图标 C#反序列化XML异常:在 XML文档(0, 0)中有一个错误“缺少根元素” C#[Win32&WinCE&WM]应用程序只能运行一个实例:MutexHelper Decimal类型截取保留N位小数向上取, Decimal类型截取保留N位小数并且不进行四舍五入操作
- WP开发:使用JSON格式传输应用数据
- c#中使用NetCDF存储二维数据的读写操作简单应用
- 如果在C#用WM_COPYDATA消息来实现两个进程之间传递数据
- c#使用dynamic关键字传输数据的用法
- 两个程序之间传递数据可以使用wm_copydata
- Unity3D 游戏引擎之C#使用Socket与HTTP连接服务器传输数据包
- 使用 WM_COPYDATA 在进程间共享数据
- 使用 Visual C# .NET 向 Microsoft Excel 2002 传输 XML 数据
- 使用 Visual C# .NET 向 Excel 工作簿传输数据
- 使用 Visual C# .NET 向 Microsoft Excel 2002 传输 XML 数据
- 如何使用 Visual C# 2005 或 Visual C# .NET 向 Excel 工作簿传输数据[转载MSDN]
- (转载)在C#用WM_COPYDATA消息来实现两个进程之间传递数据
- 使用 Visual C# .NET 向 Excel 工作簿传输数据