通過SendMessge實現的進程間通信。
0x01 自定義消息
1,WINDOWS中自定義消息的定義和使用;
(1)在WNDOWS中消息分系統消息和自定義消息。系統消息定義從0到0x3FF,使用0x400到0x7FFF定義自己的消息。Windows把0x400定義為WM_USER。如果想定義自己的一個消息,可以在WM_USER上加上一個值:
#define UM_MSG WM_USER+1
(2)另一種自定義窗口消息的方法是用RegisterWindowsMessage()函數來注冊這個消息。與在WM_USER上加上某個數相比,它的好處是不必考慮所表示的消息標識符是否超出工程的允許范圍。如:
const UINT RM_MSG = RegisterWindowMessage(L"HelloWorld");
在接收消息的程序中,需要對添加對應消息的響應處理函數,並將消息和消息處理函數關聯.
0x02 WM_COPYDATA
WM_COPYDATA消息,在win32中用來進行進程間的數據傳輸。
typedef struct tagCOPYDATASTRUCT { ULONG_PTR dwData; //自定義數據 DWORD cbData; //數據的大小(字節數) _Field_size_bytes_(cbData) PVOID lpData; //指向數據的指針 } COPYDATASTRUCT, *PCOPYDATASTRUCT;
注意:該消息只能由SendMessage()來發送,而不能使用PostMessage()。因為系統必須管理用以傳遞數據的緩沖區的生命期,如果使用了PostMessage(),數據緩沖區會在接收方(線程)有機會處理該數據之前,就被系統清除和回收。此外如果lpData指向一個帶有指針或某一擁有虛函數的對象時,也要小心處理。
LRESULT SendMessage( HWND hWnd, // 目標進程窗口句柄 UINT Msg, // WM_COPYDATA WPARAM wParam, // 發送進程的窗體句柄 LPARAM lParam // 指向COPYDATASTRUCT數據結構的指針 );
接收進程窗體句柄可以通過FindWindow函數獲取:
CWnd* DlgHwnd = FindWindow(NULL, L"Client");
源代碼:

1 // ServerDlg.cpp : 實現文件 2 // 3 4 #include "stdafx.h" 5 #include "Server.h" 6 #include "ServerDlg.h" 7 #include "afxdialogex.h" 8 9 #ifdef _DEBUG 10 #define new DEBUG_NEW 11 #endif 12 #define UM_MSG WM_USER+1 13 14 // 用於應用程序“關於”菜單項的 CAboutDlg 對話框 15 16 BOOL CStringToChar(char** DestinationString, CString& SourceString); 17 const UINT RM_MSG = RegisterWindowMessage(L"HelloWorld"); 18 class CAboutDlg : public CDialogEx 19 { 20 public: 21 CAboutDlg(); 22 23 // 對話框數據 24 #ifdef AFX_DESIGN_TIME 25 enum { IDD = IDD_ABOUTBOX }; 26 #endif 27 28 protected: 29 virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 30 31 // 實現 32 protected: 33 DECLARE_MESSAGE_MAP() 34 }; 35 36 CAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX) 37 { 38 } 39 40 void CAboutDlg::DoDataExchange(CDataExchange* pDX) 41 { 42 CDialogEx::DoDataExchange(pDX); 43 } 44 45 BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx) 46 END_MESSAGE_MAP() 47 48 49 // CServerDlg 對話框 50 51 52 53 CServerDlg::CServerDlg(CWnd* pParent /*=NULL*/) 54 : CDialogEx(IDD_SERVER_DIALOG, pParent) 55 , m_CEdit_User_Message(0) 56 , m_CEdit_Register_Message(0) 57 , m_CEdit_CopyData_Message(_T("")) 58 { 59 m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); 60 } 61 62 void CServerDlg::DoDataExchange(CDataExchange* pDX) 63 { 64 CDialogEx::DoDataExchange(pDX); 65 DDX_Text(pDX, IDC_EDIT_USER_MESSAGE, m_CEdit_User_Message); 66 DDX_Text(pDX, IDC_EDIT_REGISTER_MESSAGE, m_CEdit_Register_Message); 67 DDX_Text(pDX, IDC_EDIT_COPYDATA_MESSAGE, m_CEdit_CopyData_Message); 68 } 69 70 BEGIN_MESSAGE_MAP(CServerDlg, CDialogEx) 71 ON_WM_SYSCOMMAND() 72 ON_WM_PAINT() 73 ON_WM_QUERYDRAGICON() 74 ON_BN_CLICKED(IDC_BUTTON_USER_MESSAGE, &CServerDlg::OnBnClickedButtonUserMessage) 75 ON_BN_CLICKED(IDC_BUTTON_REGISTER_MESSAGE, &CServerDlg::OnBnClickedButtonRegisterMessage) 76 ON_BN_CLICKED(IDC_BUTTON_COPYDATA_MESSAGE, &CServerDlg::OnBnClickedButtonCopydataMessage) 77 END_MESSAGE_MAP() 78 79 80 // CServerDlg 消息處理程序 81 82 BOOL CServerDlg::OnInitDialog() 83 { 84 CDialogEx::OnInitDialog(); 85 86 // 將“關於...”菜單項添加到系統菜單中。 87 88 // IDM_ABOUTBOX 必須在系統命令范圍內。 89 ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); 90 ASSERT(IDM_ABOUTBOX < 0xF000); 91 92 CMenu* pSysMenu = GetSystemMenu(FALSE); 93 if (pSysMenu != NULL) 94 { 95 BOOL bNameValid; 96 CString strAboutMenu; 97 bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX); 98 ASSERT(bNameValid); 99 if (!strAboutMenu.IsEmpty()) 100 { 101 pSysMenu->AppendMenu(MF_SEPARATOR); 102 pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); 103 } 104 } 105 106 // 設置此對話框的圖標。 當應用程序主窗口不是對話框時,框架將自動 107 // 執行此操作 108 SetIcon(m_hIcon, TRUE); // 設置大圖標 109 SetIcon(m_hIcon, FALSE); // 設置小圖標 110 111 // TODO: 在此添加額外的初始化代碼 112 113 return TRUE; // 除非將焦點設置到控件,否則返回 TRUE 114 } 115 116 void CServerDlg::OnSysCommand(UINT nID, LPARAM lParam) 117 { 118 if ((nID & 0xFFF0) == IDM_ABOUTBOX) 119 { 120 CAboutDlg dlgAbout; 121 dlgAbout.DoModal(); 122 } 123 else 124 { 125 CDialogEx::OnSysCommand(nID, lParam); 126 } 127 } 128 129 // 如果向對話框添加最小化按鈕,則需要下面的代碼 130 // 來繪制該圖標。 對於使用文檔/視圖模型的 MFC 應用程序, 131 // 這將由框架自動完成。 132 133 void CServerDlg::OnPaint() 134 { 135 if (IsIconic()) 136 { 137 CPaintDC dc(this); // 用於繪制的設備上下文 138 139 SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0); 140 141 // 使圖標在工作區矩形中居中 142 int cxIcon = GetSystemMetrics(SM_CXICON); 143 int cyIcon = GetSystemMetrics(SM_CYICON); 144 CRect rect; 145 GetClientRect(&rect); 146 int x = (rect.Width() - cxIcon + 1) / 2; 147 int y = (rect.Height() - cyIcon + 1) / 2; 148 149 // 繪制圖標 150 dc.DrawIcon(x, y, m_hIcon); 151 } 152 else 153 { 154 CDialogEx::OnPaint(); 155 } 156 } 157 158 //當用戶拖動最小化窗口時系統調用此函數取得光標 159 //顯示。 160 HCURSOR CServerDlg::OnQueryDragIcon() 161 { 162 return static_cast<HCURSOR>(m_hIcon); 163 } 164 165 166 167 void CServerDlg::OnBnClickedButtonUserMessage() 168 { 169 // TODO: 在此添加控件通知處理程序代碼 170 UpdateData(TRUE); 171 172 CWnd* DlgHwnd = FindWindow(NULL,L"Client"); 173 if (DlgHwnd == NULL) { 174 AfxMessageBox(TEXT("No Found")); 175 return; 176 } 177 long ParameterData; 178 ParameterData = m_CEdit_User_Message; 179 DlgHwnd->SendMessage(UM_MSG, NULL, (LPARAM)ParameterData);// 發送. 180 } 181 182 183 void CServerDlg::OnBnClickedButtonRegisterMessage() 184 { 185 // TODO: 在此添加控件通知處理程序代碼 186 UpdateData(TRUE); 187 CWnd* DlgHwnd = FindWindow(NULL, L"Client"); 188 if (DlgHwnd == NULL) { 189 AfxMessageBox(TEXT("No Found")); 190 return; 191 } 192 long ParameterData; 193 ParameterData = m_CEdit_Register_Message; 194 DlgHwnd->SendMessage(RM_MSG, NULL, (LPARAM)ParameterData);// 發送. 195 196 } 197 198 199 void CServerDlg::OnBnClickedButtonCopydataMessage() 200 { 201 // TODO: 在此添加控件通知處理程序代碼 202 UpdateData(TRUE); 203 204 CWnd* DlgHwnd = FindWindow(NULL, L"Client"); 205 if (DlgHwnd == NULL) { 206 AfxMessageBox(TEXT("No Found")); 207 return; 208 } 209 char* DestinationString = NULL; 210 211 CStringToChar(&DestinationString, m_CEdit_CopyData_Message); 212 213 214 215 COPYDATASTRUCT ParameterData; // 給COPYDATASTRUCT結構賦值. 216 ParameterData.dwData = 0; 217 ParameterData.cbData = strlen(DestinationString); //注意這里 218 ParameterData.lpData = DestinationString; 219 220 DlgHwnd->SendMessage(WM_COPYDATA, NULL, (LPARAM)&ParameterData);// 發送. 221 222 if (DestinationString!=NULL) 223 { 224 delete[] DestinationString; 225 DestinationString = NULL; 226 } 227 } 228 BOOL CStringToChar(char** DestinationString, CString& SourceString) 229 { 230 if (SourceString.IsEmpty()) 231 { 232 return FALSE; 233 } 234 int SourceStringLength = SourceString.GetLength(); 235 *DestinationString = (char*)malloc((SourceStringLength * 2 + 1) * sizeof(char));//CString的長度中漢字算一個長度 236 237 if (*DestinationString == NULL) 238 { 239 return FALSE; 240 } 241 USES_CONVERSION; 242 strcpy(*DestinationString, W2A(SourceString.LockBuffer())); 243 SourceString.ReleaseBuffer(); 244 return TRUE; 245 }

1 // ClientDlg.cpp : 實現文件 2 // 3 4 #include "stdafx.h" 5 #include "Client.h" 6 #include "ClientDlg.h" 7 #include "afxdialogex.h" 8 9 #ifdef _DEBUG 10 #define new DEBUG_NEW 11 #endif 12 13 14 #define UM_MSG WM_USER+1 15 16 // 用於應用程序“關於”菜單項的 CAboutDlg 對話框 17 const UINT RM_MSG = RegisterWindowMessage(L"HelloWorld"); 18 19 class CAboutDlg : public CDialogEx 20 { 21 public: 22 CAboutDlg(); 23 24 // 對話框數據 25 #ifdef AFX_DESIGN_TIME 26 enum { IDD = IDD_ABOUTBOX }; 27 #endif 28 29 protected: 30 virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 31 32 // 實現 33 protected: 34 DECLARE_MESSAGE_MAP() 35 }; 36 37 CAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX) 38 { 39 } 40 41 void CAboutDlg::DoDataExchange(CDataExchange* pDX) 42 { 43 CDialogEx::DoDataExchange(pDX); 44 } 45 46 BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx) 47 END_MESSAGE_MAP() 48 49 50 // CClientDlg 對話框 51 52 53 54 CClientDlg::CClientDlg(CWnd* pParent /*=NULL*/) 55 : CDialogEx(IDD_CLIENT_DIALOG, pParent) 56 , m_CEdit_User_Message(0) 57 , m_CEdit_Register_Message(0) 58 , m_CEdit_CopyData_Message(_T("")) 59 { 60 m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); 61 } 62 63 void CClientDlg::DoDataExchange(CDataExchange* pDX) 64 { 65 CDialogEx::DoDataExchange(pDX); 66 DDX_Text(pDX, IDC_EDIT_USER_MESSAGE, m_CEdit_User_Message); 67 DDX_Text(pDX, IDC_EDIT_REGISTER_MESSAGE, m_CEdit_Register_Message); 68 DDX_Text(pDX, IDC_EDIT_COPYDATA_MESSAGE, m_CEdit_CopyData_Message); 69 } 70 71 BEGIN_MESSAGE_MAP(CClientDlg, CDialogEx) 72 ON_WM_SYSCOMMAND() 73 ON_WM_PAINT() 74 ON_WM_QUERYDRAGICON() 75 ON_WM_COPYDATA() 76 ON_MESSAGE(UM_MSG, (LRESULT (__thiscall CWnd::* )(WPARAM,LPARAM))OnUserReceiveMsg) 77 ON_REGISTERED_MESSAGE(RM_MSG, (LRESULT (__thiscall CWnd::* )(WPARAM,LPARAM))OnRegisterReceiveMsg) 78 END_MESSAGE_MAP() 79 80 81 // CClientDlg 消息處理程序 82 83 BOOL CClientDlg::OnInitDialog() 84 { 85 CDialogEx::OnInitDialog(); 86 87 // 將“關於...”菜單項添加到系統菜單中。 88 89 // IDM_ABOUTBOX 必須在系統命令范圍內。 90 ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); 91 ASSERT(IDM_ABOUTBOX < 0xF000); 92 93 CMenu* pSysMenu = GetSystemMenu(FALSE); 94 if (pSysMenu != NULL) 95 { 96 BOOL bNameValid; 97 CString strAboutMenu; 98 bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX); 99 ASSERT(bNameValid); 100 if (!strAboutMenu.IsEmpty()) 101 { 102 pSysMenu->AppendMenu(MF_SEPARATOR); 103 pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); 104 } 105 } 106 107 // 設置此對話框的圖標。 當應用程序主窗口不是對話框時,框架將自動 108 // 執行此操作 109 SetIcon(m_hIcon, TRUE); // 設置大圖標 110 SetIcon(m_hIcon, FALSE); // 設置小圖標 111 112 // TODO: 在此添加額外的初始化代碼 113 114 return TRUE; // 除非將焦點設置到控件,否則返回 TRUE 115 } 116 117 void CClientDlg::OnSysCommand(UINT nID, LPARAM lParam) 118 { 119 if ((nID & 0xFFF0) == IDM_ABOUTBOX) 120 { 121 CAboutDlg dlgAbout; 122 dlgAbout.DoModal(); 123 } 124 else 125 { 126 CDialogEx::OnSysCommand(nID, lParam); 127 } 128 } 129 130 // 如果向對話框添加最小化按鈕,則需要下面的代碼 131 // 來繪制該圖標。 對於使用文檔/視圖模型的 MFC 應用程序, 132 // 這將由框架自動完成。 133 134 void CClientDlg::OnPaint() 135 { 136 if (IsIconic()) 137 { 138 CPaintDC dc(this); // 用於繪制的設備上下文 139 140 SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0); 141 142 // 使圖標在工作區矩形中居中 143 int cxIcon = GetSystemMetrics(SM_CXICON); 144 int cyIcon = GetSystemMetrics(SM_CYICON); 145 CRect rect; 146 GetClientRect(&rect); 147 int x = (rect.Width() - cxIcon + 1) / 2; 148 int y = (rect.Height() - cyIcon + 1) / 2; 149 150 // 繪制圖標 151 dc.DrawIcon(x, y, m_hIcon); 152 } 153 else 154 { 155 CDialogEx::OnPaint(); 156 } 157 } 158 159 //當用戶拖動最小化窗口時系統調用此函數取得光標 160 //顯示。 161 HCURSOR CClientDlg::OnQueryDragIcon() 162 { 163 return static_cast<HCURSOR>(m_hIcon); 164 } 165 166 void CClientDlg::OnUserReceiveMsg(WPARAM wParam, LPARAM lParam) 167 { 168 m_CEdit_User_Message = long(lParam); 169 // 更新數據. 170 UpdateData(FALSE); 171 } 172 173 void CClientDlg::OnRegisterReceiveMsg(WPARAM wParam, LPARAM lParam) 174 { 175 m_CEdit_Register_Message = long(lParam); 176 // 更新數據. 177 UpdateData(FALSE); 178 } 179 180 BOOL CClientDlg::OnCopyData(CWnd* pWnd, COPYDATASTRUCT* pCopyDataStruct) 181 { 182 // TODO: 在此添加消息處理程序代碼和/或調用默認值 183 m_CEdit_CopyData_Message = (LPSTR)pCopyDataStruct->lpData; 184 m_CEdit_CopyData_Message = m_CEdit_CopyData_Message.Left(pCopyDataStruct->cbData); 185 186 // 更新數據. 187 UpdateData(FALSE); 188 return CDialogEx::OnCopyData(pWnd, pCopyDataStruct); 189 }