进程间通信

时间:2021-07-14
本文章向大家介绍进程间通信,主要包括进程间通信使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

不得不说,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值),即可以实现两个进程间的相互通信。

原文地址:https://www.cnblogs.com/stanchen/p/15012293.html