使用Windows API实现两个进程间(含窗体)的通信在Windows下的两个进程之间通信通常有多种实现方式,在.NET中,有如命名管道、消息队列、共享内存等实现方式,这篇文章要讲的是使用Windows的API来实现简单的进程间通信,这两个进程既可以都是基于C#开发,也可以都是基于C++开发,也可以是一个C#开发而另一个为C++开发,在C++开发方面,不需要额外调用Windows的API,而是可以直接使用相关方法即可。所以,这里重点要讲的就是在C#中是如何做的,而至于在C++中是如何做的将给出例子,并不做详述。

对于接收消息,只需要重写DefWndProc函数即可,对于发送消息,笔者编写了一个类MsgHandler来实现。要顺利实现消息的接收与发送,使用了Windows的API:FindWindow、SendMessage等。在C#环境中,通过DllImport来引入相应的API,代码示例如下:

// FindWindow method, using Windows API [DllImport("User32.dll", EntryPoint = "FindWindow")] private static extern int FindWindow(string lpClassName, string lpWindowName); // IsWindow method, using Windows API [DllImport("User32.dll", EntryPoint = "IsWindow")] private static extern bool IsWindow(int hWnd); // SendMessage method, using Windows API [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 ); // SendMessage method, using Windows API [DllImport("User32.dll", EntryPoint = "SendMessage")] private static extern int SendMessage( int hWnd, // handle to destination window int Msg, // message int wParam, // first message parameter string lParam // second message parameter );

笔者查阅了相关网络资源,发现很少有提及使用自定义消息来发送和接收消息的,几乎都是使用了系统消息WM_COPYDATA来实现。在本例中,笔者除了使用系统消息WM_COPYDATA来收发消息外,还将使用自定义消息来实现收发消息。不过,值得注意的是,笔者在测试过程中发现,使用自定义的消息来收发结构体时发生了一些异常,该异常提示说内存不能读,对于该问题,还有待进一步解决,当然,若是哪位前辈或朋友有遇到过该问题并已顺利解决的话,不妨告知,笔者将洗耳恭听。

消息发送类MsgHandler的代码示例如下:

using System; using System.Text; using System.Windows.Forms; using System.Diagnostics; using System.Runtime.InteropServices; namespace CommunicationTest { /// <summary> /// Send message handler class. /// Call the method "SendMessageToTargetWindow" to send /// the message what we want. /// </summary> class MsgHandler { /// <summary> /// System defined message /// </summary> private const int WM_COPYDATA = 0x004A; /// <summary> /// User defined message /// </summary> private const int WM_DATA_TRANSFER = 0x0437; // FindWindow method, using Windows API [DllImport("User32.dll", EntryPoint = "FindWindow")] private static extern int FindWindow(string lpClassName, string lpWindowName); // IsWindow method, using Windows API [DllImport("User32.dll", EntryPoint = "IsWindow")] private static extern bool IsWindow(int hWnd); // SendMessage method, using Windows API [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 ); // SendMessage method, using Windows API [DllImport("User32.dll", EntryPoint = "SendMessage")] private static extern int SendMessage( int hWnd, // handle to destination window int Msg, // message int wParam, // first message parameter string lParam // second message parameter ); /// <summary> /// CopyDataStruct /// </summary> private struct COPYDATASTRUCT { public IntPtr dwData; public int cbData; public IntPtr lpData; } /// <summary> /// Send message to target window /// </summary> /// <param name="wndName">The window name which we want to found</param> /// <param name="msg">The message to be sent, string</param> /// <returns>success or not</returns> public static bool SendMessageToTargetWindow(string wndName, string msg) { Debug.WriteLine(string.Format("SendMessageToTargetWindow: Send message to target window {0}: {1}", wndName, msg)); int iHWnd = FindWindow(null, wndName); if (iHWnd == 0) { string strError = string.Format("SendMessageToTargetWindow: The target window [{0}] was not found!", wndName); MessageBox.Show(strError, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); Debug.WriteLine(strError); return false; } else { byte[] bytData = null; bytData = Encoding.Default.GetBytes(msg); COPYDATASTRUCT cdsBuffer; cdsBuffer.dwData = (IntPtr)100; cdsBuffer.cbData = bytData.Length; cdsBuffer.lpData = Marshal.AllocHGlobal(bytData.Length); Marshal.Copy(bytData, 0, cdsBuffer.lpData, bytData.Length); // Use system defined message WM_COPYDATA to send message. int iReturn = SendMessage(iHWnd, WM_COPYDATA, 0, ref cdsBuffer); if (iReturn < 0) { string strError = string.Format("SendMessageToTargetWindow: Send message to the target window [{0}] failed!", wndName); MessageBox.Show(strError, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); Debug.WriteLine(strError); return false; } return true; } } /// <summary> /// Send message to target window /// </summary> /// <param name="wndName">The window name which we want to found</param> /// <param name="wParam">first parameter, integer</param> /// <param name="lParam">second parameter, string</param> /// <returns>success or not</returns> public static bool SendMessageToTargetWindow(string wndName, int wParam, string lParam) { Debug.WriteLine(string.Format("SendMessageToTargetWindow: Send message to target window {0}: wParam:{1}, lParam:{2}", wndName, wParam, lParam)); int iHWnd = FindWindow(null, wndName); if (iHWnd == 0) { string strError = string.Format("SendMessageToTargetWindow: The target window [{0}] was not found!", wndName); MessageBox.Show(strError, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); Debug.WriteLine(strError); return false; } else { // Use our defined message WM_DATA_TRANSFER to send message. int iReturn = SendMessage(iHWnd, WM_DATA_TRANSFER, wParam, lParam); if (iReturn < 0) { string strError = string.Format("SendMessageToTargetWindow: Send message to the target window [{0}] failed!", wndName); MessageBox.Show(strError, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); Debug.WriteLine(strError); return false; } return true; } } } }

消息接收重写了DefWndProc方法,其代码示例如下:

/// <summary> /// Override the DefWndProc function, in order to receive the message through it. /// </summary> /// <param name="m">message</param> protected override void DefWndProc(ref System.Windows.Forms.Message m) { switch (m.Msg) { // Here, we use WM_COPYDATA message to receive the COPYDATASTRUCT case WM_COPYDATA: COPYDATASTRUCT cds = new COPYDATASTRUCT(); cds = (COPYDATASTRUCT)m.GetLParam(typeof(COPYDATASTRUCT)); byte[] bytData = new byte[cds.cbData]; Marshal.Copy(cds.lpData, bytData, 0, bytData.Length); this.ProcessIncomingData(bytData); break; // Here, we use our defined message WM_DATA_TRANSFER to receive the // normal data, such as integer, string. // We had try to use our defined message to receive the COPYDATASTRUCT, // but it didn't work!! It told us that we try to access the protected // memory, it usually means that other memory has been broken. case WM_DATA_TRANSFER: int iWParam = (int)m.WParam; string sLParam = m.LParam.ToString(); this.ProcessIncomingData(iWParam, sLParam); break; default: base.DefWndProc(ref m); break; } }

消息的接收与发送最终通过一个WinForm展现出来,其代码实现如下:

using System; using System.Text; using System.Windows.Forms; using System.Runtime.InteropServices; namespace CommunicationTest { public partial class FrmTest : Form { /// <summary> /// System defined message /// </summary> private const int WM_COPYDATA = 0x004A; /// <summary> /// User defined message /// </summary> private const int WM_DATA_TRANSFER = 0x0437; /// <summary> /// CopyDataStruct /// </summary> public struct COPYDATASTRUCT { public IntPtr dwData; public int cbData; public IntPtr lpData; } public FrmTest() { InitializeComponent(); } /// <summary> /// Override the DefWndProc function, in order to receive the message through it. /// </summary> /// <param name="m">message</param> protected override void DefWndProc(ref System.Windows.Forms.Message m) { switch (m.Msg) { // Here, we use WM_COPYDATA message to receive the COPYDATASTRUCT case WM_COPYDATA: COPYDATASTRUCT cds = new COPYDATASTRUCT(); cds = (COPYDATASTRUCT)m.GetLParam(typeof(COPYDATASTRUCT)); byte[] bytData = new byte[cds.cbData]; Marshal.Copy(cds.lpData, bytData, 0, bytData.Length); this.ProcessIncomingData(bytData); break; // Here, we use our defined message WM_DATA_TRANSFER to receive the // normal data, such as integer, string. // We had try to use our defined message to receive the COPYDATASTRUCT, // but it didn't work!! It told us that we try to access the protected // memory, it usually means that other memory has been broken. case WM_DATA_TRANSFER: int iWParam = (int)m.WParam; string sLParam = m.LParam.ToString(); this.ProcessIncomingData(iWParam, sLParam); break; default: base.DefWndProc(ref m); break; } } /// <summary> /// Process the incoming data /// </summary> /// <param name="data">incoming data</param> private void ProcessIncomingData(byte[] bytesData) { string strRevMsg = "Receive message: " + Encoding.Default.GetString(bytesData); lstReceivedMsg.Items.Add(strRevMsg); } /// <summary> /// Process the incoming data /// </summary> /// <param name="iWParam">a integer parameter</param> /// <param name="sLParam">a string parameter</param> private void ProcessIncomingData(int iWParam, string sLParam) { StringBuilder strBuilder = new StringBuilder(); strBuilder.Append("wParam: "); strBuilder.Append(iWParam.ToString()); strBuilder.Append(", lParam: "); strBuilder.Append(sLParam); lstReceivedMsg.Items.Add(strBuilder.ToString()); } private void FrmTest_Load(object sender, EventArgs e) { this.Text = "First Test Form"; this.txtCurrentWndName.Text = "First Test Form"; this.txtTargetWndName.Text = "Second Test Form"; } private void txtCurrentWndName_TextChanged(object sender, EventArgs e) { this.Text = txtCurrentWndName.Text; } /// <summary> /// Send message to the target window with system defined message WM_COPYDATA /// </summary> private void btnSend1_Click(object sender, EventArgs e) { string strWndName = this.txtTargetWndName.Text; // Check the target window name is null/empty or not if (string.IsNullOrEmpty(strWndName)) { MessageBox.Show("The target window name must not be null or empty!", "Information", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); return; } string strMsg = this.txtSendingMsg.Text; // Check the sending message is null/empty or not if (string.IsNullOrEmpty(strMsg)) { MessageBox.Show("The sending message must not be null or empty!", "Information", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); return; } // Send message to the target window bool bReturn = MsgHandler.SendMessageToTargetWindow(strWndName, strMsg); } /// <summary> /// Send message to the target window with user defined message WM_DATA_TRANSFER /// </summary> private void btnSend2_Click(object sender, EventArgs e) { string strWndName = this.txtTargetWndName.Text; // Check the target window name is null/empty or not if (string.IsNullOrEmpty(strWndName)) { MessageBox.Show("The target window name must not be null or empty!", "Information", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); return; } string strWParam = this.txtWParam.Text; string strLParam = this.txtLParam.Text; // Check the sending message is null/empty or not if (string.IsNullOrEmpty(strWParam) || string.IsNullOrEmpty(strLParam)) { MessageBox.Show("The sending message must not be null or empty!", "Information", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); return; } int iWParam = 0; // Convert string to integer try { iWParam = Int32.Parse(strWParam); } catch (Exception ex) { MessageBox.Show("Convert string to integer exception: " + ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } // Send message to the target window bool bReturn = MsgHandler.SendMessageToTargetWindow(strWndName, iWParam, strLParam); } } }

通过上述的C#部分的代码,已经可以实现两个C#窗体间的通信,其界面截图如下图所示:

那么,在C++中又是如何实现的呢?这个其实也是很简单的。要实现消息的收发,同理也要重写WindowProc以便于接收消息,而通过调用方法亦可实现消息的发送。
    对于消息接收,如果是系统消息,可以通过OnCopyData(CWnd* pWnd, COPYDATASTRUCT* pCopyDataStruct)事件完成;如果是自定义消息,可以通过重写WindowProc完成。代码示例如下:

BOOL CTestDlg::OnCopyData(CWnd* pWnd, COPYDATASTRUCT* pCopyDataStruct) { // TODO: 在此添加消息处理程序代码和/或调用默认值 DWORD dwSize = pCopyDataStruct->cbData; CString szData;// = (LPCTSTR)(pCopyDataStruct->lpData); TCHAR* ptchar = new TCHAR[dwSize+1]; memcpy( ptchar, pCopyDataStruct->lpData, dwSize ); ptchar[dwSize] = TEXT('/0'); szData = ptchar; // TODO: Add some code here to handler the message delete[] ptchar; return CDialog::OnCopyData(pWnd, pCopyDataStruct); } LRESULT CTestDlg::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) { // TODO: 在此添加专用代码和/或调用基类 COPYDATASTRUCT szCpyData; switch ( message ) { case WM_DATA_TRANSFER: szCpyData = *((PCOPYDATASTRUCT)lParam); // TODO: Add some code here to handler the message break; default: break; } return CDialog::WindowProc(message, wParam, lParam); }
    对于消息发送,只需要调用形如SendMessage(m_hwndMsg, WM_DATA_TRANSFER, wParam, lParam)方法即可实现,lParam参数可以是PCOPYDATASTRUCT等。

通过上面的介绍,相信已经可以轻松实现两个进程间(含窗体)的通信的,使用这样的方法,既简单又能够满足大部分的应用需求,不失为一种简便的方法。

转载于:https://www.cnblogs.com/bile/p/5545887.html

c# 进程间的通信实现之一简单字符串收发相关推荐

  1. 进程间的通信——共享内存

    下面将讲解进程间通信的另一种方式,使用共享内存. 一.什么是共享内存 顾名思义,共享内存就是允许两个不相关的进程访问同一个逻辑内存.共享内存是在两个正在运行的进程之间共享和传递数据的一种非常有效的方式 ...

  2. 网络编程之 进程间的通信之管道的使用

    如何使用管道是进程间通信的关键 博主先声明一下,关于处理进程创建以及销毁的方法.        "子进程究竟何时终止????调用waitpid函数后还要无休止的等待子进程终止吗???&quo ...

  3. python进程间通信时间开销_python 进程间的通信

    python3,进程间的通信 本文来源于python 3.5版本的官方文档 multiprocessing模块为进程间通信提供了两种方法: 1.进程队列queue The Queue class is ...

  4. 第十章 进程间的通信 之 Java/Android多线程开发(二)

    文章目录 (一)Java 多线程开发 1.1)线程状态 1.2)线程控制方法 (1.2.1)Synchronized (1.2.2)Volatile (1.2.3)ReentrantLock 1.3) ...

  5. Linux之本地进程间Socket通信

    文章目录 一.Sokcet 二.Sokcet API (一).sockaddr 结构: (二).struct socketaddr_in : (三).Struct socketaddr_un (四). ...

  6. 深刻理解 Linux 进程间七大通信(IPC)

    前言 网络编程是 Linux C/C++的面试重点,今天我就来聊一聊进程间通信的问题,文章末尾列出了参考资料,希望帮助到大家. 篇幅有点长,希望大家耐心阅读. Linux 下的进程通信手段基本上是从 ...

  7. 【《现代操作系统 第4版》】4、进程间的通信之互斥

    买面包问题 假设有两个人A.B要采购面包,首先查看冰箱中是否有面包,如果没有则离开家去超市购买面包,买来后把面包放到冰箱. 假设A.B的日程如下图所示.显然这会导致面包超买,如何保证最多只有一个人去买 ...

  8. linux+Qt 下利用D-Bus进行进程间高效通信的三种方式

    linux+Qt 下利用D-Bus进行进程间高效通信的三种方式 原文链接: https://www.cnblogs.com/wwang/archive/2010/10/27/1862552.html ...

  9. 同步线程和进程间的通信

    最近回去学习了一下进程和进程间的通信,有时候很多东西久不看了也就一下子忘了== 这里面有好几个互斥对象使用线程的 1 void mListText(CString str) 2 { 3 m_list_ ...

  10. Android 使用AIDL实现进程间的通信

    在Android中,如果我们需要在不同进程间实现通信,就需要用到AIDL技术去完成. AIDL(android Interface Definition Language)是一种接口定义语言,编译器通 ...

最新文章

  1. 常用javascript函数
  2. Java和js常用表达式
  3. android控件属性
  4. kvm直通sata_基于KVM的SRIOV直通配置及性能测试
  5. java 接口式自定义回调函数
  6. layui自带验证体系:手机号验证、邮箱验证、必填项非空验证、数字验证(含代码、案例)
  7. 详解学习C#的方法和步骤
  8. access 打印预览 代码_TSC TTP-244条码打印机如何批量打印二维码
  9. 冤冤相报何时了?奥克斯、格力再互怼,“周一见”
  10. oracle----删除数据
  11. 使用kubeadm安装kubenetes
  12. 【原】SDWebImage源码阅读(一)
  13. C#移除对象中的属性(model类或集合等)JObject
  14. 计算机应用中格式刷怎么用,Word中格式刷怎么用? -电脑资料
  15. 3D图形渲染及数字图像处理算法相关文集
  16. 2012年8月21日
  17. leetcode-SQL-1148. 文章浏览 I
  18. 数据结构最常用的排序算法一(冒泡、插入、选择)-Java实现
  19. linux创建桥接接口,Linux创建桥接网络
  20. 一川烟草,满城飞絮,梅子黄时雨

热门文章

  1. 分享网上一篇产品经理的经验总结--产品经理九步法
  2. PVS中TFTP的隐藏配置
  3. 消费者反映鸡蛋难吃后的37种回答方法
  4. Linux内核基础--事件通知链(notifier chain)
  5. mysql 5.5 innodb 优化_mysql 5.5 -- innodb buffer pool优化
  6. Linux音频驱动-OSS和ALSA声音系统简介及其比较
  7. 【组播技术入门 01】IP组播概述
  8. Android-7.0-Nuplayer概述
  9. 为线程命名——prctl
  10. PostgreSQL 角色与用户管理介绍