C# wpf 实现窗体间消息传输
本文介绍WPF使用windows 自带的User32.dll中的SendMessage和FindWindow函数实现两个窗体应用程序的消息传递。
其中发送消息和winform的实现方式类似,但接收消息由于wpf的windows类没有类似于Form类的DefWndProc来处理消息,所以会略显复杂。
一、导入外部dll
User32.dll在c盘windows\system32目录下,将它复制到VS的wpf项目中bin\debug文件夹下即可。WM_COPYDATA作为系统消息。
//定义一个全局变量作为消息,WM_COPYDATA消息的标识符为0x004A
public const int WM_COPYDATA = 0x004A;
//使用windows系统提供的user32.dll
[DllImport("User32.dll", EntryPoint = "SendMessage")]
private static extern int SendMessage(int hWnd, int Msg, int wParam, IntPtr lParam);
[DllImport("User32.dll", EntryPoint = "FindWindow")]
private static extern int FindWindow(string lpClassName, string lpWindowName);
二、定义传递信息的结构体
这个结构体承载消息的信息,之后以Intptr的形式作为SendMessage的参数。
//定义传递信息的结构体,之后将其转化为Intptr后作为SendMessage的一个参数
public struct COPYDATASTRUCT
{
public IntPtr dwData;
public int cbData;
[MarshalAs(UnmanagedType.LPStr)]
public string lpData;
}
三、发送消息窗体按钮函数
点击发送消息的窗体的发送按钮,发送textbox1中的消息。
需要注意的是其中用了c#自带的marshal类来实现struct与Inptr之间的转化。
//发送消息
private void Button_Click(object sender, RoutedEventArgs e)
{
//通过窗体类名获取被发送对象的句柄,此处该对象为window2
int hWnd = FindWindow(null, "Window2");
if (hWnd == 0)
{
MessageBox.Show("未找到消息接受者!");
}
else
{
byte[] sarr = System.Text.Encoding.Default.GetBytes(textBox1.Text);
int len = sarr.Length;
COPYDATASTRUCT cds;
cds.dwData = (IntPtr)Convert.ToInt16(0);//可以是任意值,本例中不用到
cds.cbData = len + 1;//指定lpData内存区域的字节数
cds.lpData = "MainWindow:" + textBox1.Text;//发送给目标窗口所在进程的数据
//使用marshal将struct转化为intptr
// Initialize unmanged memory to hold the struct.
IntPtr pnt = Marshal.AllocHGlobal(Marshal.SizeOf(cds));
Marshal.StructureToPtr(cds, pnt, false);
SendMessage(hWnd, WM_COPYDATA, 0, pnt);
richTextBox1.AppendText("MainWindow:" + textBox1.Text + "\n");
}
textBox1.Text = "";
}
四、接收消息窗体函数
4.1 创建HwndSource对象
创建HwndSource对象,然后利用其AddHook方法来将所有的windows消息附加到一个现有的事件中。
WndProc函数就是WPF中类似于winform重载DefWndProc来处理消息的步骤。
//将此函数注册到window2窗体的SourceInitialized事件后,WndProc函数就会被用于处理收到的消息
void WSInitialized(object sender, EventArgs e)
{
HwndSource hs = PresentationSource.FromVisual(this) as HwndSource;
hs.AddHook(new HwndSourceHook(WndProc));
}
4.2 WndProc消息处理函数
根据msg消息值决定如何处理消息,仍然用Marshal类将Intptr句柄转化回struct。
//消息处理
protected IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
switch (msg)
{
case WM_COPYDATA:
COPYDATASTRUCT cds = new COPYDATASTRUCT();
Type t = cds.GetType();
//使用marshal将intptr转换为struct
cds = (COPYDATASTRUCT )Marshal.PtrToStructure (lParam , typeof(COPYDATASTRUCT));
string strResult = cds.lpData + "\n";
richTextBox1.AppendText(strResult);
break;
}
return IntPtr.Zero;
}
参考文献:
在WPF中使用WindowProc处理消息
WPF中的WndProc
C# byte[]、struct、intptr的相互转换