MFC-不同程序进程间通信
方法一:使用注册消息
示例一:
// fasongDlg.cpp: 实现文件 // #include "pch.h" #include "framework.h" #include "fasong.h" #include "fasongDlg.h" #include "afxdialogex.h" #ifdef _DEBUG #define new DEBUG_NEW #endif // 用于应用程序“关于”菜单项的 CAboutDlg 对话框 class CAboutDlg : public CDialogEx { public: CAboutDlg(); // 对话框数据 #ifdef AFX_DESIGN_TIME enum { IDD = IDD_ABOUTBOX }; #endif protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 // 实现 protected: DECLARE_MESSAGE_MAP() }; CAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX) { } void CAboutDlg::DoDataExchange(CDataExchange* pDX) { CDialogEx::DoDataExchange(pDX); } BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx) END_MESSAGE_MAP() // CfasongDlg 对话框 CfasongDlg::CfasongDlg(CWnd* pParent /*=nullptr*/) : CDialogEx(IDD_FASONG_DIALOG, pParent) { m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); } void CfasongDlg::DoDataExchange(CDataExchange* pDX) { CDialogEx::DoDataExchange(pDX); } BEGIN_MESSAGE_MAP(CfasongDlg, CDialogEx) ON_WM_SYSCOMMAND() ON_WM_PAINT() ON_WM_QUERYDRAGICON() ON_BN_CLICKED(IDC_BUTTON1, &CfasongDlg::OnBnClickedButton1) END_MESSAGE_MAP() const UINT WM_xiaoxihao = ::RegisterWindowMessage(_T("liming"));//给窗口增加消息 // CfasongDlg 消息处理程序 BOOL CfasongDlg::OnInitDialog() { CDialogEx::OnInitDialog(); // 将“关于...”菜单项添加到系统菜单中。 // IDM_ABOUTBOX 必须在系统命令范围内。 ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); ASSERT(IDM_ABOUTBOX < 0xF000); CMenu* pSysMenu = GetSystemMenu(FALSE); if (pSysMenu != nullptr) { BOOL bNameValid; CString strAboutMenu; bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX); ASSERT(bNameValid); if (!strAboutMenu.IsEmpty()) { pSysMenu->AppendMenu(MF_SEPARATOR); pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); } } // 设置此对话框的图标。 当应用程序主窗口不是对话框时,框架将自动 // 执行此操作 SetIcon(m_hIcon, TRUE); // 设置大图标 SetIcon(m_hIcon, FALSE); // 设置小图标 // TODO: 在此添加额外的初始化代码 return TRUE; // 除非将焦点设置到控件,否则返回 TRUE } void CfasongDlg::OnSysCommand(UINT nID, LPARAM lParam) { if ((nID & 0xFFF0) == IDM_ABOUTBOX) { CAboutDlg dlgAbout; dlgAbout.DoModal(); } else { CDialogEx::OnSysCommand(nID, lParam); } } // 如果向对话框添加最小化按钮,则需要下面的代码 // 来绘制该图标。 对于使用文档/视图模型的 MFC 应用程序, // 这将由框架自动完成。 void CfasongDlg::OnPaint() { if (IsIconic()) { CPaintDC dc(this); // 用于绘制的设备上下文 SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0); // 使图标在工作区矩形中居中 int cxIcon = GetSystemMetrics(SM_CXICON); int cyIcon = GetSystemMetrics(SM_CYICON); CRect rect; GetClientRect(&rect); int x = (rect.Width() - cxIcon + 1) / 2; int y = (rect.Height() - cyIcon + 1) / 2; // 绘制图标 dc.DrawIcon(x, y, m_hIcon); } else { CDialogEx::OnPaint(); } } //当用户拖动最小化窗口时系统调用此函数取得光标 //显示。 HCURSOR CfasongDlg::OnQueryDragIcon() { return static_cast<HCURSOR>(m_hIcon); } void CfasongDlg::OnBnClickedButton1() { ::PostMessage(HWND_BROADCAST, WM_xiaoxihao, 0, 0);//发送消息 }
接收消息进程
h文件
// jiesouDlg.h: 头文件 // #pragma once // CjiesouDlg 对话框 class CjiesouDlg : public CDialogEx { // 构造 public: CjiesouDlg(CWnd* pParent = nullptr); // 标准构造函数 // 对话框数据 #ifdef AFX_DESIGN_TIME enum { IDD = IDD_JIESOU_DIALOG }; #endif protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 // 实现 protected: HICON m_hIcon; // 生成的消息映射函数 virtual BOOL OnInitDialog(); afx_msg void OnSysCommand(UINT nID, LPARAM lParam); afx_msg void OnPaint(); afx_msg HCURSOR OnQueryDragIcon(); afx_msg LRESULT Onxiaoxi(WPARAM wParam, LPARAM lParam);//声明消息响应函数 DECLARE_MESSAGE_MAP() public: afx_msg void OnBnClickedButton1(); };
cpp函数
// jiesouDlg.cpp: 实现文件 // #include "pch.h" #include "framework.h" #include "jiesou.h" #include "jiesouDlg.h" #include "afxdialogex.h" #ifdef _DEBUG #define new DEBUG_NEW #endif const UINT WM_xiaoxihao = ::RegisterWindowMessage(_T("liming"));//给窗口增加消息 // 用于应用程序“关于”菜单项的 CAboutDlg 对话框 class CAboutDlg : public CDialogEx { public: CAboutDlg(); // 对话框数据 #ifdef AFX_DESIGN_TIME enum { IDD = IDD_ABOUTBOX }; #endif protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 // 实现 protected: DECLARE_MESSAGE_MAP() }; CAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX) { } void CAboutDlg::DoDataExchange(CDataExchange* pDX) { CDialogEx::DoDataExchange(pDX); } BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx) END_MESSAGE_MAP() // CjiesouDlg 对话框 CjiesouDlg::CjiesouDlg(CWnd* pParent /*=nullptr*/) : CDialogEx(IDD_JIESOU_DIALOG, pParent) { m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); } void CjiesouDlg::DoDataExchange(CDataExchange* pDX) { CDialogEx::DoDataExchange(pDX); } BEGIN_MESSAGE_MAP(CjiesouDlg, CDialogEx) ON_WM_SYSCOMMAND() ON_WM_PAINT() ON_WM_QUERYDRAGICON() ON_BN_CLICKED(IDC_BUTTON1, &CjiesouDlg::OnBnClickedButton1) ON_REGISTERED_MESSAGE(WM_xiaoxihao, Onxiaoxi) //把消息响应函数与消息号关联起来 END_MESSAGE_MAP() // CjiesouDlg 消息处理程序 BOOL CjiesouDlg::OnInitDialog() { CDialogEx::OnInitDialog(); // 将“关于...”菜单项添加到系统菜单中。 // IDM_ABOUTBOX 必须在系统命令范围内。 ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); ASSERT(IDM_ABOUTBOX < 0xF000); CMenu* pSysMenu = GetSystemMenu(FALSE); if (pSysMenu != nullptr) { BOOL bNameValid; CString strAboutMenu; bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX); ASSERT(bNameValid); if (!strAboutMenu.IsEmpty()) { pSysMenu->AppendMenu(MF_SEPARATOR); pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); } } // 设置此对话框的图标。 当应用程序主窗口不是对话框时,框架将自动 // 执行此操作 SetIcon(m_hIcon, TRUE); // 设置大图标 SetIcon(m_hIcon, FALSE); // 设置小图标 // TODO: 在此添加额外的初始化代码 return TRUE; // 除非将焦点设置到控件,否则返回 TRUE } void CjiesouDlg::OnSysCommand(UINT nID, LPARAM lParam) { if ((nID & 0xFFF0) == IDM_ABOUTBOX) { CAboutDlg dlgAbout; dlgAbout.DoModal(); } else { CDialogEx::OnSysCommand(nID, lParam); } } // 如果向对话框添加最小化按钮,则需要下面的代码 // 来绘制该图标。 对于使用文档/视图模型的 MFC 应用程序, // 这将由框架自动完成。 void CjiesouDlg::OnPaint() { if (IsIconic()) { CPaintDC dc(this); // 用于绘制的设备上下文 SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0); // 使图标在工作区矩形中居中 int cxIcon = GetSystemMetrics(SM_CXICON); int cyIcon = GetSystemMetrics(SM_CYICON); CRect rect; GetClientRect(&rect); int x = (rect.Width() - cxIcon + 1) / 2; int y = (rect.Height() - cyIcon + 1) / 2; // 绘制图标 dc.DrawIcon(x, y, m_hIcon); } else { CDialogEx::OnPaint(); } } //当用户拖动最小化窗口时系统调用此函数取得光标 //显示。 HCURSOR CjiesouDlg::OnQueryDragIcon() { return static_cast<HCURSOR>(m_hIcon); } LRESULT CjiesouDlg::Onxiaoxi(WPARAM wParam, LPARAM lParam) { AfxMessageBox(_T("接收到消息")); return LRESULT(); } void CjiesouDlg::OnBnClickedButton1() { }
在接收端,如果不用消息宏定义,可以重载PreTranslateMessage,截取消息,然后处理:
BOOL CMainFrame::PreTranslateMessage(MSG* pMsg)
{
if(pMsg->message == WM_UPDATE_ALARMFILTER)
{
// 消息处理
}
return CDialog::PreTranslateMessage(pMsg);
}
实例工程下载:
链接:https://pan.baidu.com/s/1tL9misWDRanZiMbILTel8A
提取码:6666
链接:https://pan.baidu.com/s/18h2mdGy5A-UP_7s5DhBflQ
提取码:6666
实例二:用BroadcastSystemMessage广播消息
方法二:通过WM_COPYDATA消息
发送程序:
// fasongADlg.cpp: 实现文件 // #include "pch.h" #include "framework.h" #include "fasongA.h" #include "fasongADlg.h" #include "afxdialogex.h" #ifdef _DEBUG #define new DEBUG_NEW #endif // 用于应用程序“关于”菜单项的 CAboutDlg 对话框 class CAboutDlg : public CDialogEx { public: CAboutDlg(); // 对话框数据 #ifdef AFX_DESIGN_TIME enum { IDD = IDD_ABOUTBOX }; #endif protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 // 实现 protected: DECLARE_MESSAGE_MAP() }; CAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX) { } void CAboutDlg::DoDataExchange(CDataExchange* pDX) { CDialogEx::DoDataExchange(pDX); } BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx) END_MESSAGE_MAP() // CfasongADlg 对话框 CfasongADlg::CfasongADlg(CWnd* pParent /*=nullptr*/) : CDialogEx(IDD_FASONGA_DIALOG, pParent) { m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); } void CfasongADlg::DoDataExchange(CDataExchange* pDX) { CDialogEx::DoDataExchange(pDX); } BEGIN_MESSAGE_MAP(CfasongADlg, CDialogEx) ON_WM_SYSCOMMAND() ON_WM_PAINT() ON_WM_QUERYDRAGICON() ON_BN_CLICKED(IDC_BUTTON1, &CfasongADlg::OnBnClickedButton1) END_MESSAGE_MAP() // CfasongADlg 消息处理程序 BOOL CfasongADlg::OnInitDialog() { CDialogEx::OnInitDialog(); // 将“关于...”菜单项添加到系统菜单中。 // IDM_ABOUTBOX 必须在系统命令范围内。 ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); ASSERT(IDM_ABOUTBOX < 0xF000); CMenu* pSysMenu = GetSystemMenu(FALSE); if (pSysMenu != nullptr) { BOOL bNameValid; CString strAboutMenu; bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX); ASSERT(bNameValid); if (!strAboutMenu.IsEmpty()) { pSysMenu->AppendMenu(MF_SEPARATOR); pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); } } // 设置此对话框的图标。 当应用程序主窗口不是对话框时,框架将自动 // 执行此操作 SetIcon(m_hIcon, TRUE); // 设置大图标 SetIcon(m_hIcon, FALSE); // 设置小图标 // TODO: 在此添加额外的初始化代码 return TRUE; // 除非将焦点设置到控件,否则返回 TRUE } void CfasongADlg::OnSysCommand(UINT nID, LPARAM lParam) { if ((nID & 0xFFF0) == IDM_ABOUTBOX) { CAboutDlg dlgAbout; dlgAbout.DoModal(); } else { CDialogEx::OnSysCommand(nID, lParam); } } // 如果向对话框添加最小化按钮,则需要下面的代码 // 来绘制该图标。 对于使用文档/视图模型的 MFC 应用程序, // 这将由框架自动完成。 void CfasongADlg::OnPaint() { if (IsIconic()) { CPaintDC dc(this); // 用于绘制的设备上下文 SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0); // 使图标在工作区矩形中居中 int cxIcon = GetSystemMetrics(SM_CXICON); int cyIcon = GetSystemMetrics(SM_CYICON); CRect rect; GetClientRect(&rect); int x = (rect.Width() - cxIcon + 1) / 2; int y = (rect.Height() - cyIcon + 1) / 2; // 绘制图标 dc.DrawIcon(x, y, m_hIcon); } else { CDialogEx::OnPaint(); } } //当用户拖动最小化窗口时系统调用此函数取得光标 //显示。 HCURSOR CfasongADlg::OnQueryDragIcon() { return static_cast<HCURSOR>(m_hIcon); } void CfasongADlg::OnBnClickedButton1() { // TODO: 在此添加控件通知处理程序代码 CString strWindowTitle = _T("MFCRecv"); HWND hRecvWnd = ::FindWindow(NULL, strWindowTitle.GetBuffer(0)); CString strDataToSend = _T("Hello,这是霸道小明");//要发送的数据 if (hRecvWnd != NULL && ::IsWindow(hRecvWnd)) { //数据的封装 COPYDATASTRUCT cpd; cpd.dwData = 0;//要传递给应用程序的数据 //ULONG_PTR dwData为自定义数据,按照自己习惯设置就好,不影响对象的传输 cpd.cbData = strDataToSend.GetLength() * sizeof(TCHAR);//传递数据的大小 // DWORD cbData; //要是这个变量的值设置错误,就会导致WM_COPYDATA传输数据失败 cpd.lpData = (PVOID)strDataToSend.GetBuffer(0); //PVOID lpData 传输的数据。使用简单的数据最好,例如char数组。 //本人在程序中使用了string对象,发现在子进程不能接收到正常的数据,使用char数组却很正常。 //有可能跟string对象不能跨进程访问有关,读者如果知道原因的话请在评论区告诉我,谢谢 //使用WM_COPYDATA时要用SendMessage而不能使用PostMessage,因为SendMessage是阻塞的, //会等待消息响应窗体处理消息完毕后再返回;而PostMessage是异步的, //这样就可能会导致当消息响应窗体接收到WM_COPYDATA的时候,COPYDATASTRUCT对象已经被析构了, //导致访问数据发生异常 //由于使用SendMessage,所以不应该在WM_COPYDATA中处理数据,可以在消息响应窗体的WM_COPYDATA中 //先把COPYDATASTRUCT对象中的数据复制出来,通过自定义消息发送到消息响应窗体,然后立即返回, //来减少父进程的阻塞时间。这样就把处理数据的代码放在自定义消息处了 ::SendMessage(hRecvWnd, WM_COPYDATA, (WPARAM)(AfxGetApp()->m_pMainWnd), (LPARAM)&cpd); //AfxGetApp()->m_pMainWnd 获得主窗口的句柄 } strDataToSend.ReleaseBuffer(); }
实例工程下载:
链接:https://pan.baidu.com/s/1kEYnFexNGvcMgNOW5Mgd2w
提取码:6666
接受程序:
// jiesouADlg.cpp: 实现文件 // #include "pch.h" #include "framework.h" #include "jiesouA.h" #include "jiesouADlg.h" #include "afxdialogex.h" #ifdef _DEBUG #define new DEBUG_NEW #endif // 用于应用程序“关于”菜单项的 CAboutDlg 对话框 class CAboutDlg : public CDialogEx { public: CAboutDlg(); // 对话框数据 #ifdef AFX_DESIGN_TIME enum { IDD = IDD_ABOUTBOX }; #endif protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 // 实现 protected: DECLARE_MESSAGE_MAP() }; CAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX) { } void CAboutDlg::DoDataExchange(CDataExchange* pDX) { CDialogEx::DoDataExchange(pDX); } BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx) END_MESSAGE_MAP() // CjiesouADlg 对话框 CjiesouADlg::CjiesouADlg(CWnd* pParent /*=nullptr*/) : CDialogEx(IDD_JIESOUA_DIALOG, pParent) { m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); } void CjiesouADlg::DoDataExchange(CDataExchange* pDX) { CDialogEx::DoDataExchange(pDX); } BEGIN_MESSAGE_MAP(CjiesouADlg, CDialogEx) ON_WM_SYSCOMMAND() ON_WM_PAINT() ON_WM_QUERYDRAGICON() ON_WM_COPYDATA() END_MESSAGE_MAP() // CjiesouADlg 消息处理程序 BOOL CjiesouADlg::OnInitDialog() { CDialogEx::OnInitDialog(); // 将“关于...”菜单项添加到系统菜单中。 // IDM_ABOUTBOX 必须在系统命令范围内。 ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); ASSERT(IDM_ABOUTBOX < 0xF000); CMenu* pSysMenu = GetSystemMenu(FALSE); if (pSysMenu != nullptr) { BOOL bNameValid; CString strAboutMenu; bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX); ASSERT(bNameValid); if (!strAboutMenu.IsEmpty()) { pSysMenu->AppendMenu(MF_SEPARATOR); pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); } } // 设置此对话框的图标。 当应用程序主窗口不是对话框时,框架将自动 // 执行此操作 SetIcon(m_hIcon, TRUE); // 设置大图标 SetIcon(m_hIcon, FALSE); // 设置小图标 // TODO: 在此添加额外的初始化代码 HWND hWnd2 = GetSafeHwnd(); ::SetWindowText(hWnd2, _T("MFCRecv")); return TRUE; // 除非将焦点设置到控件,否则返回 TRUE } void CjiesouADlg::OnSysCommand(UINT nID, LPARAM lParam) { if ((nID & 0xFFF0) == IDM_ABOUTBOX) { CAboutDlg dlgAbout; dlgAbout.DoModal(); } else { CDialogEx::OnSysCommand(nID, lParam); } } // 如果向对话框添加最小化按钮,则需要下面的代码 // 来绘制该图标。 对于使用文档/视图模型的 MFC 应用程序, // 这将由框架自动完成。 void CjiesouADlg::OnPaint() { if (IsIconic()) { CPaintDC dc(this); // 用于绘制的设备上下文 SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0); // 使图标在工作区矩形中居中 int cxIcon = GetSystemMetrics(SM_CXICON); int cyIcon = GetSystemMetrics(SM_CYICON); CRect rect; GetClientRect(&rect); int x = (rect.Width() - cxIcon + 1) / 2; int y = (rect.Height() - cyIcon + 1) / 2; // 绘制图标 dc.DrawIcon(x, y, m_hIcon); } else { CDialogEx::OnPaint(); } } //当用户拖动最小化窗口时系统调用此函数取得光标 //显示。 HCURSOR CjiesouADlg::OnQueryDragIcon() { return static_cast<HCURSOR>(m_hIcon); } BOOL CjiesouADlg::OnCopyData(CWnd* pWnd, COPYDATASTRUCT* pCopyDataStruct) { //WM_COPYDATA消息的处理函数 //当有消息发送过来时就会响应这个函数 //通过解析参数COPYDATASTRUCT* pCopyDataStruct就可以获得发送过来的数据了 //使用WM_COPYDATA时要用SendMessage而不能使用PostMessage,因为SendMessage是阻塞的,会等待消息响应窗体处理消息完毕后再返回;而PostMessage是异步的,这样就可能会导致当消息响应窗体接收到WM_COPYDATA的时候,COPYDATASTRUCT对象已经被析构了,导致访问数据发生异常 //COPYDATA结构体的实质依然是共享内存,区别是这一片特殊的共享内存由操作系统管理而不用用户手动申请管理 //WM_COPYDATA适合小数据量的进程间通信,大数据量可能造成内存问题,以及界面卡死,因为消息的发送形式是同步的 //pCopyDataStruct 就是LPARAM传送过来的数据 //pWnd就是WPARAM传送过来的数据 LPCTSTR szText = (LPCTSTR)(pCopyDataStruct->lpData); DWORD dwLength = (DWORD)pCopyDataStruct->cbData; TCHAR szRecvText[1024] = { 0 }; memcpy(szRecvText, szText, dwLength); MessageBox(szRecvText, _T("收到消息"), MB_OK); return CDialogEx::OnCopyData(pWnd, pCopyDataStruct); }
实例工程下载:
链接:https://pan.baidu.com/s/1Xpl8PujHq073XXuMMQmyJw
提取码:6666