用SendMessage用于进程间通信使用自定义消息,String含在Struct里,接收方却得到null?
在网上找了一下可以用“结构体封装string字段”,但是我试过,接收方可以收到消息,得到的String却是null,不知道为什么?如果要传其它数据类型,如byte,int之类的应该怎么传送?
发送方: public const int WM_USER = 0x500;
public const int RF_CMD = WM_USER + 13;
public struct RFDataStruct
{
public int rfLength;
public string rfData;
} byte rfCmd = 0; [DllImport("user32.dll")]
public static extern bool SendMessage(IntPtr hWnd, int Msg, int wParam, ref RFDataStruct lparam); private void buttonSend_Click(object sender, EventArgs e)
{
Process[] vProcesses = Process.GetProcessesByName("PorcessReceiveUserDefinedMessageDemo"); // 查询目标进程
if (vProcesses.Length <= 0)
vProcesses = Process.GetProcessesByName("PorcessReceiveUserDefinedMessageDemo.vshost"); //Debug调试进程
if (vProcesses.Length <= 0)
{
MessageBox.Show("目标进程没有找到!");
return;
} if (comboBoxRF.Text == comboBoxRF.Items[0].ToString()) rfCmd = 0;
else if (comboBoxRF.Text == comboBoxRF.Items[1].ToString()) rfCmd = 1;
else if (comboBoxRF.Text == comboBoxRF.Items[2].ToString()) rfCmd = 2; //SelectedText不行,始终为空
else rfCmd = 3;
string rfCmdString = rfCmd.ToString("X2"); RFDataStruct rfMessage = new RFDataStruct();
rfMessage.rfData = rfCmdString;
rfMessage.rfLength = rfMessage.rfData.Length;
foreach (Process vProcess in vProcesses)
{
bool returnValue3 = SendMessage(vProcess.MainWindowHandle, RF_CMD, 1, ref rfMessage);
}
}接收方: public const int WM_USER = 0x500;
public const int RF_CMD = WM_USER + 13; public struct RFDataStruct
{
public string rfData;
public int rfLength;
} protected override void DefWndProc(ref Message m)
{
switch (m.Msg)
{
case RF_CMD:
RFDataStruct rfDataStruct = new RFDataStruct();
Type type = rfDataStruct.GetType();
rfDataStruct = (RFDataStruct)m.GetLParam(type);
string rfCmd = rfDataStruct.rfData;
//string rfCmd = Marshal.PtrToStringBSTR(m.LParam);
textBox1.Text = rfCmd;
break;
default:
base.DefWndProc(ref m);
break;
}
//base.WndProc(ref m);
}rfCmd为null,rfData为0,而且发现用SendMessage有时会出现异常“外部组件发生异常”。
以下是我从网上找到的例子,唯一不同的是它是在同一个进程的两个窗口之间传递,在接收方窗体里没有定义结构体,直接用的发送窗体的结构体,它的是可以收到的。
发送窗体 //自定义的消息
public const int USER = 0x500;
public const int MYMESSAGE = USER + 1; public Form2()
{
InitializeComponent();
} IntPtr HD; public Form2(IntPtr hd)
{
InitializeComponent();
HD = hd;
} private void button1_Click(object sender, EventArgs e)
{
IntPtr ptr = FindWindow(null, "Form1");//获取接收消息的窗体句柄
//消息构建
My_lParam m = new My_lParam();
m.s = textBox1.Text;
m.i = m.s.Length;
SendMessage(ptr, MYMESSAGE, 1, ref m);//发送消息
} public struct My_lParam
{
public int i;
public string s;
} //消息发送API
[DllImport("User32.dll", EntryPoint = "SendMessage")]
private static extern int SendMessage(
IntPtr hWnd, // 信息发往的窗口的句柄
int Msg, // 消息ID
int wParam, // 参数1
ref My_lParam lParam
); [DllImport("User32.dll", EntryPoint = "FindWindow")]
private extern static IntPtr FindWindow(string lpClassName, string lpWindowName); 接收窗体:public const int USER = 0x500;
public const int MYMESSAGE = USER + 1;
public Form1()
{
InitializeComponent();
} private void button1_Click(object sender, EventArgs e)
{
Form2 f = new Form2(this.Handle);
f.Show();
} ///重写窗体的消息处理函数DefWndProc,从中加入自己定义消息 MYMESSAGE 的检测的处理入口
protected override void DefWndProc(ref Message m)
{
switch (m.Msg)
{
//接收自定义消息MYMESSAGE,并显示其参数
case MYMESSAGE: Form2.My_lParam ml = new Form2.My_lParam();
Type t = ml.GetType();
ml = (Form2.My_lParam)m.GetLParam(t);
label1.Text = ml.s; //SendCustomMessage.SENDDATASTRUCT myData = new SendCustomMessage.SENDDATASTRUCT();//这是创建自定义信息的结构
//Type mytype = myData.GetType();
//myData = (SendCustomMessage.SENDDATASTRUCT)m.GetLParam(mytype);//这里获取的就是作为LParam参数发送来的信息的结构
//textBox1.Text = myData.lpData; //显示收到的自定义信息
break;
default:
base.DefWndProc(ref m);
break;
} }SendMessage 自定义消息
在网上找了一下可以用“结构体封装string字段”,但是我试过,接收方可以收到消息,得到的String却是null,不知道为什么?如果要传其它数据类型,如byte,int之类的应该怎么传送?
发送方: public const int WM_USER = 0x500;
public const int RF_CMD = WM_USER + 13;
public struct RFDataStruct
{
public int rfLength;
public string rfData;
} byte rfCmd = 0; [DllImport("user32.dll")]
public static extern bool SendMessage(IntPtr hWnd, int Msg, int wParam, ref RFDataStruct lparam); private void buttonSend_Click(object sender, EventArgs e)
{
Process[] vProcesses = Process.GetProcessesByName("PorcessReceiveUserDefinedMessageDemo"); // 查询目标进程
if (vProcesses.Length <= 0)
vProcesses = Process.GetProcessesByName("PorcessReceiveUserDefinedMessageDemo.vshost"); //Debug调试进程
if (vProcesses.Length <= 0)
{
MessageBox.Show("目标进程没有找到!");
return;
} if (comboBoxRF.Text == comboBoxRF.Items[0].ToString()) rfCmd = 0;
else if (comboBoxRF.Text == comboBoxRF.Items[1].ToString()) rfCmd = 1;
else if (comboBoxRF.Text == comboBoxRF.Items[2].ToString()) rfCmd = 2; //SelectedText不行,始终为空
else rfCmd = 3;
string rfCmdString = rfCmd.ToString("X2"); RFDataStruct rfMessage = new RFDataStruct();
rfMessage.rfData = rfCmdString;
rfMessage.rfLength = rfMessage.rfData.Length;
foreach (Process vProcess in vProcesses)
{
bool returnValue3 = SendMessage(vProcess.MainWindowHandle, RF_CMD, 1, ref rfMessage);
}
}接收方: public const int WM_USER = 0x500;
public const int RF_CMD = WM_USER + 13; public struct RFDataStruct
{
public string rfData;
public int rfLength;
} protected override void DefWndProc(ref Message m)
{
switch (m.Msg)
{
case RF_CMD:
RFDataStruct rfDataStruct = new RFDataStruct();
Type type = rfDataStruct.GetType();
rfDataStruct = (RFDataStruct)m.GetLParam(type);
string rfCmd = rfDataStruct.rfData;
//string rfCmd = Marshal.PtrToStringBSTR(m.LParam);
textBox1.Text = rfCmd;
break;
default:
base.DefWndProc(ref m);
break;
}
//base.WndProc(ref m);
}rfCmd为null,rfData为0,而且发现用SendMessage有时会出现异常“外部组件发生异常”。
以下是我从网上找到的例子,唯一不同的是它是在同一个进程的两个窗口之间传递,在接收方窗体里没有定义结构体,直接用的发送窗体的结构体,它的是可以收到的。
发送窗体 //自定义的消息
public const int USER = 0x500;
public const int MYMESSAGE = USER + 1; public Form2()
{
InitializeComponent();
} IntPtr HD; public Form2(IntPtr hd)
{
InitializeComponent();
HD = hd;
} private void button1_Click(object sender, EventArgs e)
{
IntPtr ptr = FindWindow(null, "Form1");//获取接收消息的窗体句柄
//消息构建
My_lParam m = new My_lParam();
m.s = textBox1.Text;
m.i = m.s.Length;
SendMessage(ptr, MYMESSAGE, 1, ref m);//发送消息
} public struct My_lParam
{
public int i;
public string s;
} //消息发送API
[DllImport("User32.dll", EntryPoint = "SendMessage")]
private static extern int SendMessage(
IntPtr hWnd, // 信息发往的窗口的句柄
int Msg, // 消息ID
int wParam, // 参数1
ref My_lParam lParam
); [DllImport("User32.dll", EntryPoint = "FindWindow")]
private extern static IntPtr FindWindow(string lpClassName, string lpWindowName); 接收窗体:public const int USER = 0x500;
public const int MYMESSAGE = USER + 1;
public Form1()
{
InitializeComponent();
} private void button1_Click(object sender, EventArgs e)
{
Form2 f = new Form2(this.Handle);
f.Show();
} ///重写窗体的消息处理函数DefWndProc,从中加入自己定义消息 MYMESSAGE 的检测的处理入口
protected override void DefWndProc(ref Message m)
{
switch (m.Msg)
{
//接收自定义消息MYMESSAGE,并显示其参数
case MYMESSAGE: Form2.My_lParam ml = new Form2.My_lParam();
Type t = ml.GetType();
ml = (Form2.My_lParam)m.GetLParam(t);
label1.Text = ml.s; //SendCustomMessage.SENDDATASTRUCT myData = new SendCustomMessage.SENDDATASTRUCT();//这是创建自定义信息的结构
//Type mytype = myData.GetType();
//myData = (SendCustomMessage.SENDDATASTRUCT)m.GetLParam(mytype);//这里获取的就是作为LParam参数发送来的信息的结构
//textBox1.Text = myData.lpData; //显示收到的自定义信息
break;
default:
base.DefWndProc(ref m);
break;
} }SendMessage 自定义消息
发送intptr
Marshal.stringtoptrauto
原因是,两个进程的内存空间是独立的。在某个进程有效的指针,对另外一个进程而言,就是垃圾。解决:
方法一、建议不用Windows消息(局限会越来越大),用Socket,Named Pipe,WCF等等。
方法二、用WM_COPYDATA,系统会帮你拷贝数据到另外一个进程。
其实我之前也试过发送方用Marshal.StringToHGlobalAnsi,接收方用Marshal.PtrToStringAnsi,收到的都是乱码。
如果想用自定义消息传送String,或者是byte整型数据,该怎么传送呢?
因为对方已经用自定义消息收了,如果要改其它方式,对方也要改。
你知道如何在两进程间用自定义消息在两进程间传递byte等之类的整型。
发送方: public const int WM_USER = 0x500;
public const int RF_CMD = WM_USER + 13;
public struct RFDataStruct
{
public int rfLength;
public string rfData;
} byte rfCmd = 0; [DllImport("user32.dll")]
public static extern bool SendMessage(IntPtr hWnd, int Msg, int wParam, ref RFDataStruct lparam); [DllImport("user32.dll")]
public static extern bool SendMessage(IntPtr hWnd, int Msg, int wParam, IntPtr lparam); [DllImport("user32.dll")]
public static extern bool SendMessage(IntPtr hWnd, int Msg, byte wParam, int lparam); private void buttonSend_Click(object sender, EventArgs e)
{
Process[] vProcesses = Process.GetProcessesByName("PorcessReceiveUserDefinedMessageDemo"); // 查询目标进程
if (vProcesses.Length <= 0)
vProcesses = Process.GetProcessesByName("PorcessReceiveUserDefinedMessageDemo.vshost"); //Debug调试进程
if (vProcesses.Length <= 0)
{
MessageBox.Show("目标进程没有找到!");
return;
} if (comboBoxRF.Text == comboBoxRF.Items[0].ToString()) rfCmd = 0;
else if (comboBoxRF.Text == comboBoxRF.Items[1].ToString()) rfCmd = 1;
else if (comboBoxRF.Text == comboBoxRF.Items[2].ToString()) rfCmd = 2; //SelectedText不行,始终为空
else rfCmd = 3;
string rfCmdString = rfCmd.ToString("X2"); //RFDataStruct rfMessage = new RFDataStruct();
//rfMessage.rfData = rfCmdString;
//rfMessage.rfLength = rfMessage.rfData.Length; //IntPtr rfIntPtr = Marshal.StringToHGlobalAuto(rfCmdString); //乱码
// IntPtr rfIntPtr = Marshal.StringToHGlobalUni(rfCmdString); //乱码
//IntPtr rfIntPtr = Marshal.AllocHGlobal(1);
//Marshal.WriteByte(rfIntPtr, rfCmd); foreach (Process vProcess in vProcesses)
{
//bool returnValue3 = SendMessage(vProcess.MainWindowHandle, RF_CMD, 1, ref rfMessage);
//bool returnValue3 = SendMessage(vProcess.MainWindowHandle, RF_CMD, 1, rfIntPtr);
bool returnValue3 = SendMessage(vProcess.MainWindowHandle, RF_CMD, rfCmd, 1);
}
//Marshal.FreeHGlobal(rfIntPtr);
}接收方:
public const int WM_USER = 0x500;
public const int RF_CMD = WM_USER + 13; public struct RFDataStruct
{
public string rfData;
public int rfLength;
} protected override void DefWndProc(ref Message m)
{
switch (m.Msg)
{
case RF_CMD:
//RFDataStruct rfDataStruct = new RFDataStruct();
//Type type = rfDataStruct.GetType();
//rfDataStruct = (RFDataStruct)m.GetLParam(type);
//string rfCmd = rfDataStruct.rfData; //string rfCmd = Marshal.PtrToStringAuto(m.LParam);
//string rfCmd = Marshal.PtrToStringUni(m.LParam);
//textBox1.Text = rfCmd; //byte rfCmd = Marshal.ReadByte(m.LParam);
//textBox1.Text = rfCmd.ToString(); //byte rfCmd= (byte)m.GetLParam(typeof(byte)); //有异常
byte rfCmd = (byte)m.WParam;
textBox1.Text = rfCmd.ToString();
break;
default:
base.DefWndProc(ref m);
break;
}
//base.WndProc(ref m);
}