C# 跨进程通信
IM项目刚开始,由于IM客户端要与VMEETING通信,所以就做了技术调研,跨进程通信,我们使用的是windows api的findwindow找到窗口,然后用send message通信。(此方案只适用于接收端有window的场景)
接收端代码:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.IO;
namespace ProcessServer
{
public partial class FrmProcessServer : Form
{
public FrmProcessServer()
{
InitializeComponent();
}
#region const data
const int WM_COPYDATA = 0x004A;
public struct COPYDATASTRUCT
{
public IntPtr dwData;
public int cbData;
[MarshalAs(UnmanagedType.LPStr)]
public string lpData;
}
#endregion
[DllImport("user32")]
public static extern bool ChangeWindowMessageFilter(uint msg, int flags);
#region windows api functions
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);
File.WriteAllText("D:/processText.txt", "recieved:" + mystr.lpData);
lstMessageList.Items.Add(mystr.lpData);
break;
default:
base.DefWndProc(ref m);
break;
}
}
#endregion
private void btnListen_Click(object sender, EventArgs e)
{
}
private void FrmProcessServer_Load(object sender, EventArgs e)
{
ChangeWindowMessageFilter(WM_COPYDATA, 1);
}
}
}
发送端代码:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace ProcessClient
{
public partial class FrmClientSender : Form
{
public FrmClientSender()
{
InitializeComponent();
}
//define const datas
const int WM_COPYDATA = 0x004A;
public enum ChangeWindowMessageFilterFlags : uint
{
Add = 1, Remove = 2
};
public struct COPYDATASTRUCT
{
public IntPtr dwData;
public int cbData;
[MarshalAs(UnmanagedType.LPStr)]
public string lpData;
}
#region Dll Import
[DllImport("User32.dll", EntryPoint = "FindWindow")]
private static extern IntPtr FindWindow(string lpClassName,
string lpWindowName);
[DllImport("user32.dll", EntryPoint = "FindWindowEx")]
private static extern IntPtr FindWindowEx(IntPtr hwndParent,
IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
[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")]
public static extern bool PostMessage(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32")]
public static extern uint RegisterWindowMessage(string msg);
[DllImport("user32")]
public static extern bool ChangeWindowMessageFilter(uint msg, ChangeWindowMessageFilterFlags flags);
#endregion
#region public methods
private static void SendMessageToProcess(string processWindowName, string message)
{
IntPtr WINDOWHANDLER = FindWindow(null, processWindowName);
if ((int)WINDOWHANDLER == 0)
{
MessageBox.Show("reciver not found!");
}
else
{
//send message
byte[] sarr = System.Text.Encoding.Default.GetBytes(message);
int len = sarr.Length;
COPYDATASTRUCT cds;
cds.dwData = (IntPtr)100;
cds.lpData = message;
cds.cbData = len + 1;
SendMessage((int)WINDOWHANDLER, WM_COPYDATA, 0, ref cds);
}
}
#endregion
private void FrmClientSender_Load(object sender, EventArgs e)
{
}
private void btnSend_Click(object sender, EventArgs e)
{
SendMessageToProcess(txtReciver.Text, txtMessage.Text);
}
}
}
注:vista或win7中引入了uac机制,当以管理员身份运行时,仅仅调用send message这个api给接收端发是收不到的,接收端需要加上这句: ChangeWindowMessageFilter(WM_COPYDATA, 1) //告诉操作系统那条消息不要被过滤掉。