进程间通信
不得不说,workaround很香,然而还是要谨慎使用,因为有时候我们为了cover之前的workaround,又不得不继续寻找新的workaround。。。
正是因为嵌入外部应用,将视觉窗口嵌入子控件后,出现了新的问题,就是之前提过的,视觉使用的插件(log4net)不兼容嵌入模式,嵌入后,视觉界面的窗口无法显示log,为了解决这一问题,采用了进程间通信的方式,通过视觉应用发送log数据到上位机程序,间接实现在窗口上显示视觉log数据。
进程间通信主要是通过调用User32.dll中的SendMessage函数来实现的
//定义结构体,用于进程间发送/接收消息
public struct COPYDATASTRUCT
{
public IntPtr dwData;
public int cbData;
[MarshalAs(UnmanagedType.LPStr)]
public string lpData;
}
//调用SendMessage函数
[DllImport("User32.dll", EntryPoint = "SendMessage")]
private static extern int SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, ref COPYDATASTRUCT lParam);
private const int WM_COPYDATA = 0x004A;
接收消息:
/// <summary>
/// 当一个应用程序传递数据给另一个应用程序时发送此消息
/// </summary>
protected override void OnSourceInitialized(EventArgs e)
{
base.OnSourceInitialized(e);
HwndSource hwndSource = PresentationSource.FromVisual(this) as HwndSource;
if (hwndSource != null)
{
IntPtr handle = hwndSource.Handle;
hwndSource.AddHook(new HwndSourceHook(WndProc));
}
}
/// <summary>
/// 接收窗口消息
/// </summary>
IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr IParam, ref bool handled)
{
if (msg == WM_COPYDATA)
{
COPYDATASTRUCT cds = (COPYDATASTRUCT)Marshal.PtrToStructure(IParam, typeof(COPYDATASTRUCT));
string rec = cds.lpData;
//接收到消息后逻辑处理
logHelper.VisionLog(rec);
if (rec == "接收到的消息")
{
...
}
}
return hwnd;
}
发送消息:
/// <summary>
/// 发送信息
/// </summary>
public static void SendExternalApp(string msg)
{
Process[] processes = Process.GetProcessesByName(ExternalAppName);
if (processes.Length == 1)
{
IntPtr hWnd = processes[0].MainWindowHandle;
byte[] sByte = System.Text.Encoding.Default.GetBytes(msg);
int len = sByte.Length;
COPYDATASTRUCT cds;
cds.dwData = (IntPtr)0;
cds.cbData = len + 1;
cds.lpData = msg;
SendMessage(hWnd, WM_COPYDATA, IntPtr.Zero, ref cds);
}
else if (processes.Length > 1)
{
MessageBox.Show($"{ExternalAppName}进程多开,请关闭多余进程后重试");
}
else
{
MessageBox.Show($"{ExternalAppName}进程未开启,发送信息失败");
}
}
发送方应用使用同样的代码(修改ExternalAppName值),即可以实现两个进程间的相互通信。

浙公网安备 33010602011771号