1.函数定义
使用WPF框架的C#窗体应用程序可以使用SendMessage方法实现进程间通信,SendMessage属于Windows API宏,可以将指定的消息发送到一个或多个窗口,直到窗口程序处理完消息再返回,和PostMessage方法不同,PostMessage是将一个消息寄送到一个线程的消息队列后就立即返回。
2.函数原型
SendMessage的函数原型为:
LRESULT SendMessage(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM IParam)
参数定义为:
hWnd:其窗口程序将接收消息的窗口的句柄。如果此参数为HWND_BROADCAST,则消息将被发送到系统中所有顶层窗口,包括无效或不可见的非自身拥有的窗口、被覆盖的窗口和弹出式窗口,但消息不被发送到子窗口。
Msg:指定被发送的消息。
wParam:指定附加的消息特定信息。
IParam:指定附加的消息特定信息。
返回值:返回值指定消息处理的结果,依赖于所发送的消息。
3.可能需要的引用
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading;
// 导出SendMessage函数
[DllImport("User32.dll",EntryPoint = "SendMessage")]
private static extern intSendMessage(IntPtr hWnd, int Msg, IntPtrwParam, ref COPYDATASTRUCTlParam);
// 导出FindWindow函数,用于找到目标窗口所在进程
[DllImport("User32.dll",EntryPoint = "FindWindow")]
private static extern intFindWindow(string lpClassName, string lpWindowName);
4.自定义消息结构体
使用SendMessage进行进程间通信时,可以发送具有自定义结构体的消息,从而实现更多的通信功能,例如操纵程序的运行,自定义结构体的示例代码如下:
const int WM_COPYDATA= 0x004A; // 固定数值,不可更改
public struct COPYDATASTRUCT
{
public IntPtr dwData; // 任意值
public int cbData; // 指定lpData内存区域的字节数
[MarshalAs(UnmanagedType.LPStr)]
public string lpData; // 发送给目标窗口所在进程的数据
}
上述自定义结构体可以将字符串发送给目标进程。
5.发送消息
发送消息的程序先通过枚举进程获得目标进程句柄,然后将消息封装进自定义结构体并发送给目标进程,示例代码如下:
// 待发送消息
string s = "start";
// 枚举进程
Process[] procs = Process.GetProcesses();
foreach (Process p in procs)
{
if(p.ProcessName.Equals("Demo"))
{
// 获取目标进程句柄
IntPtr hWnd = p.MainWindowHandle;
// 封装消息
byte[] sarr = System.Text.Encoding.Default.GetBytes(s);
int len = sarr.Length;
COPYDATASTRUCT cds2;
cds2.dwData = (IntPtr)0;
cds2.cbData = len + 1;
cds2.lpData = s;
// 发送消息
SendMessage(hWnd, WM_COPYDATA, IntPtr.Zero, refcds2);
}
}
6.接收消息
接收消息的程序需要在MainWindow.xaml.cs文件中重写OnSourceInitialized函数,设置钩子,用于截获消息函数,示例代码如下:
protected override void OnSourceInitialized(EventArgse)
{
base.OnSourceInitialized(e);
HwndSourcehwndSource = PresentationSource.FromVisual(this) as HwndSource;
if(hwndSource != null)
{
IntPtrhandle = hwndSource.Handle;
hwndSource.AddHook(new HwndSourceHook(WndProc));
}
}
用于接收消息并执行自定义行为的消息函数示例代码如下:
IntPtr WndProc(IntPtrhwnd, int msg, IntPtrwParam, IntPtr lParam, ref bool handled)
{
if(msg == WM_COPYDATA)
{
COPYDATASTRUCT cds = (COPYDATASTRUCT)Marshal.PtrToStructure(lParam, typeof(COPYDATASTRUCT)); // 接收封装的消息
string rece = cds.lpData; // 获取消息内容
// 自定义行为
if(rece == "start")
{
…
}
}
return hwnd;
}