windows消息传送(自定义消息和WM_COPYDATA)
通过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 }