请教几个关于"在C#中用WM_COPYDATA消息来实现进程间通信"的问题
代码如下:
//---------------------------------------------------
//发送方:
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Runtime.InteropServices;
namespace WinFormSendMsg
{
public class Form1 : System.Windows.Forms.Form
{
private System.Windows.Forms.TextBox textBox1;
private System.Windows.Forms.Button button1;
private System.ComponentModel.Container components = null;
const int WM_COPYDATA = 0x004A;
public Form1()
{
InitializeComponent();
}
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
private void InitializeComponent()
{
this.textBox1 = new System.Windows.Forms.TextBox();
this.button1 = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// textBox1
//
this.textBox1.Location = new System.Drawing.Point(184, 24);
this.textBox1.Name = "textBox1 ";
this.textBox1.Size = new System.Drawing.Size(128, 21);
this.textBox1.TabIndex = 0;
this.textBox1.Text = "textBox1 ";
//
// button1
//
this.button1.Location = new System.Drawing.Point(344, 16);
this.button1.Name = "button1 ";
this.button1.Size = new System.Drawing.Size(112, 32);
this.button1.TabIndex = 1;
this.button1.Text = "button1 ";
this.button1.Click += new System.EventHandler(this.button1_Click);
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(6, 14);
this.ClientSize = new System.Drawing.Size(536, 142);
this.Controls.AddRange(new System.Windows.Forms.Control[] {
this.button1,
this.textBox1});
this.Name = "Form1 ";
this.Text = "发送方窗体 ";
this.ResumeLayout(false);
}
static void Main()
{
Application.Run(new Form1());
}
[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);
private void button1_Click(object sender, System.EventArgs e)
{
int WINDOW_HANDLER = FindWindow(null,@ "接收方窗体 "); // 1
if(WINDOW_HANDLER == 0)
{
}
else
{
byte[] sarr = System.Text.Encoding.Default.GetBytes(this.textBox1.Text);
int len = sarr.Length;
COPYDATASTRUCT cds;
cds.dwData = (IntPtr) 100; // 2
cds.lpData = this.textBox1.Text;
cds.cbData = len + 1;
SendMessage(WINDOW_HANDLER, WM_COPYDATA, 0, ref cds);
}
}
}
public struct COPYDATASTRUCT
{
public IntPtr dwData;
public int cbData;
[MarshalAs(UnmanagedType.LPStr)] // 3
public string lpData;
}
}
//---------------------------------------------------
//接受方
//---------------------------------------------------
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Runtime.InteropServices;
namespace WindowsFormGetMsg
{
public class Form1 : System.Windows.Forms.Form
{
private System.Windows.Forms.TextBox textBox1;
private System.ComponentModel.Container components = null;
const int WM_COPYDATA = 0x004A;
public Form1()
{
InitializeComponent();
}
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
private void InitializeComponent()
{
this.textBox1 = new System.Windows.Forms.TextBox();
this.SuspendLayout();
//
// textBox1
//
this.textBox1.Location = new System.Drawing.Point(176, 32);
this.textBox1.Name = "textBox1 ";
this.textBox1.Size = new System.Drawing.Size(160, 21);
this.textBox1.TabIndex = 0;
this.textBox1.Text = "textBox1 ";
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(6, 14);
this.ClientSize = new System.Drawing.Size(432, 266);
this.Controls.AddRange(new System.Windows.Forms.Control[] {
this.textBox1});
this.Name = "Form1 ";
this.Text = "接收方窗体 ";
this.ResumeLayout(false);
}
static void Main()
{
Application.Run(new Form1());
}
protected override void DefWndProc(ref System.Windows.Forms.Message m)
{
switch(m.Msg)
{
case WM_COPYDATA:
COPYDATASTRUCT mystr = new COPYDATASTRUCT();
Type mytype = mystr.GetType();
mystr =(COPYDATASTRUCT)m.GetLParam(mytype);
this.textBox1.Text =mystr.lpData;
break;
default:
base.DefWndProc(ref m);
break;
}
}
}
public struct COPYDATASTRUCT
{
public IntPtr dwData;
public int cbData;
[MarshalAs(UnmanagedType.LPStr)]
public string lpData;
}
}
---------------------------------------------------
问题如下:
1. 在代码中标注1处,如果不需要通过一个form来接收,比如我的工程里面就没有form,那我该如何接收?
2.能否讲解一下标注2处的含义,这个是什么意思呢?我查了查,
DWORD dwData;//用户定义数据
那么它这个是什么意思? 如果我的lpdata是一个结构或者类,那这个地方应该如何处理?
3.同样,标注3处说明了什么,我不写这段可以吗? 如果的lpdata是个类,那么我该写什么呢?(我觉得好像写成类没必要,传递的是一些信息,用struct足够了)
[解决办法]
int WINDOW_HANDLER = FindWindow(null,@ "接收方窗体 "); // 1
WM_COPYDATA是两个进程之间的通讯,并且双方都要有消息循环在执行。
在C#中,没有窗体,如果可以启动消息循环,也可以通讯,
不过我不知道有什么方法:)
cds.dwData = (IntPtr) 100; // 2
该语句不影响你其他两个变量的值,可任意写。
[MarshalAs(UnmanagedType.LPStr)] // 3
说明封送到非托管的方式,
如果是结构,会比较麻烦,我是用非托管方式解决的。
[解决办法]
using
IntPtr p = Marshal.StructureToPtr(
object structure,
IntPtr ptr,
bool fDeleteOld
);
封送到非托管内存,再传IntPtr
[解决办法]
平台调用本来就麻烦,
hdt(倦怠)这种方式你可以试试
但以前我做过一个项目,用该方式是不行的,可能是结构比较复杂:)
我有一点很纳闷,怎没就不能用非托管了?
个人感觉非托管也相当安全:)
[解决办法]
项目-》属性-》生成-》允许不安全代码 点上
class TestCopy
{
// The unsafe keyword allows pointers to be used within the following method:
static unsafe void Copy(byte[] src, int srcIndex, byte[] dst, int dstIndex, int count)
{
if (src == null || srcIndex < 0 ||
dst == null || dstIndex < 0 || count < 0)
{
throw new System.ArgumentException();
}
int srcLen = src.Length;
int dstLen = dst.Length;
if (srcLen - srcIndex < count || dstLen - dstIndex < count)
{
throw new System.ArgumentException();
}
// The following fixed statement pins the location of the src and dst objects
// in memory so that they will not be moved by garbage collection.
fixed (byte* pSrc = src, pDst = dst)
{
byte* ps = pSrc;
byte* pd = pDst;
// Loop over the count in blocks of 4 bytes, copying an integer (4 bytes) at a time:
for (int i = 0 ; i < count / 4 ; i++)
{
*((int*)pd) = *((int*)ps);
pd += 4;
ps += 4;
}
// Complete the copy by moving any bytes that weren 't moved in blocks of 4:
for (int i = 0; i < count % 4 ; i++)
{
*pd = *ps;
pd++;
ps++;
}
}
}
static void Main()
{
byte[] a = new byte[100];
byte[] b = new byte[100];
for (int i = 0; i < 100; ++i)
{
a[i] = (byte)i;
}
Copy(a, 0, b, 0, 100);
System.Console.WriteLine( "The first 10 elements are: ");
for (int i = 0; i < 10; ++i)
{
System.Console.Write(b[i] + " ");
}
System.Console.WriteLine( "\n ");
}
}
来自MSDN
[解决办法]
有关平台调用数据类型的信息
http://msdn.microsoft.com/library/chs/default.asp?url=/library/CHS/cpguide/html/cpconplatforminvokedatatypes.asp
[解决办法]
如果lpData里面是struct类型数据
WholeInfo wi=(WholeInfo)System.Runtime.InteropServices.Marshal.PtrToStructure(IntPtr, typeof(WholeInfo));
这样就可以得到结构了。
struct CopyDataStruct
{
public int dwData;
public int cbData;
public IntPtr lpData;
}
您看看你的定义跟我的一样么?void*是指针,你一定需要将其定义为IntPtr数据类型,你的是string,一样么?还有dwData是DWORD,Specifies up to 32 bits of data to be passed to the receiving application.
你定义成IntPtr有什么意思,直接定义成int就可以了,具体的数据定义参考
有关平台调用数据类型的信息
http://msdn.microsoft.com/library/chs/default.asp?url=/library/CHS/cpguide/html/cpconplatforminvokedatatypes.asp
先把这里搞规范了,要不就有可能出现这样那样的问题,