1.自定义消息ID。
#define WM_MY_MESSAGE (WM_USER+100) WM_USER为windows系统为非系统消息保留的ID,这里至少要用100,因为其它控件的消息会占用一部分。
2. 定义消息处理函数。
消息处理函数为消息目标类的成员函数。首先应该在.h 文件中声明。这里以主窗口类为例,主窗口类名 CMainDialog,则首先在CMainDialog.h声明消息处理函数。
protected:
afx_msg LRESULT OnMyMessage(WPARAM wParam, LPARAM lParam);
3.在CMainDialog.cpp中实现消息处理函数
LPESULT CMainDialog::OnMyMessage(WPARAM wParam, LPARAM lParam)
{
// TODO: 处理用户自定义消息
...
return 0;
}
4.在CMainDialog.cpp中映射消息ID和消息处理函数
BEGIN_MESSAGE_MAP(CMainFrame, CMDIFrameWnd)
ON_WM_CREATE()
ON_WM_TIMER()
ON_MESSAGE(WM_MY_MESSAGE, OnMyMessage)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
在创建线程的时候将主窗口句柄作为参数传入线程,就可以用 PostMessage传递消息了。
SendMessage函数功能描述:将指定的消息发送到一个或多个窗口。此函数为指定的窗口调用窗口过程,直到窗口过程处理完消息后才返回。
Postmessage函数则是将消息放入消息队列里,并立即返回。
常见问题
1)使用SendMessage来实现剪切、复制和粘贴
1 | SendMessage(hwnd, WM_COPY, 0, 0); |
2 | SendMessage(hwnd, WM_CUT, 0, 0); |
3 | SendMessage(hwnd, WM_PASTE, 0, 0); |
2)SendMessage与PostMessage的区别
PostMessage将消息放入消息队列后马上返回,而SendMessage直到窗口过程处理完消息后才返回。
3)SendMessage发送WM_COPYDATA消息在进程间传送数据
WM_COPYDATA消息主要目的是允许在进程间传递少量只读数据。SDK文档推荐用户使用SendMessage()函数,接收方在数据复制完成前不返回,这样发送方就不可能删除和修改数据。
例如:
1 | std:string strData = "VC知识库 VCKBASE.COM"; |
2 | COPYDATASTRUCT cds; |
3 | cds.dwData = 0; |
4 | cds.cbData = strData.Length(); |
5 | cds.lpData = strData.c_str(); |
6 | ::SendMessage(hwnd, WM_COPYDATA, NULL, (LPARAM)&cds); |
3、PostThreadMessage有时会失败,报1444错误(Invalid thread identifier. ),其实这不一定是线程不存在的原因,也有可能是线程不存在消息队列(message queue)造成的。事实上,并不是每个thread都有message queue,那如何让thread具有呢? 答案是,至少调用message相关的function一次,比如GetMessage,PeekMessage。
4、如果是postthreadmessage动态分配的memory给另外一个thread,要注意内存的正确释放。并且PostThreadMessage不能够post WM_COPYDATE之类的同步消息,否则会报错!
5、最好不要使用PostThreadMessage post message给一个窗口,使用PostMessage替代。
1 #include <windows.h> 2 #include <cstdio> 3 #include <process.h> 4 #define MY_MSG WM_USER+100 5 const int MAX_INFO_SIZE = 20; 6 HANDLE hStartEvent; // thread start event 7 // thread function 8 unsigned __stdcall fun(void *param) 9 { 10 printf("thread fun start 11 12 13 \n"); 14 MSG msg; 15 PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE); 16 if(!SetEvent(hStartEvent)) //set thread start event 17 { 18 printf("set start event failed,errno:%d\n",::GetLastError()); 19 return 1; 20 } 21 22 while(true) 23 { 24 if(GetMessage(&msg,0,0,0)) //get msg from message queue 25 { 26 switch(msg.message) 27 { 28 case MY_MSG: 29 char * pInfo = (char *)msg.wParam; 30 printf("recv %s\n",pInfo); 31 delete[] pInfo; 32 break; 33 } 34 } 35 }; 36 return 0; 37 } 38 int main() 39 { 40 HANDLE hThread; 41 unsigned nThreadID; 42 hStartEvent = ::CreateEvent(0,FALSE,FALSE,0); //create thread start event 43 if(hStartEvent == 0) 44 { 45 printf("create start event failed,errno:%d\n",::GetLastError()); 46 return 1; 47 } 48 //start thread 49 hThread = (HANDLE)_beginthreadex( NULL, 0, &fun, NULL, 0, &nThreadID ); 50 if(hThread == 0) 51 { 52 printf("start thread failed,errno:%d\n",::GetLastError()); 53 CloseHandle(hStartEvent); 54 return 1; 55 } 56 //wait thread start event to avoid PostThreadMessage return errno:1444 57 ::WaitForSingleObject(hStartEvent,INFINITE); 58 CloseHandle(hStartEvent); 59 int count = 0; 60 while(true) 61 { 62 char* pInfo = new char[MAX_INFO_SIZE]; //create dynamic msg 63 sprintf(pInfo,"msg_%d",++count); 64 if(!PostThreadMessage(nThreadID,MY_MSG,(WPARAM)pInfo,0))//post thread msg 65 { 66 printf("post message failed,errno:%d\n",::GetLastError()); 67 delete[] pInfo; 68 } 69 ::Sleep(1000); 70 } 71 CloseHandle(hThread); 72 return 0; 73 }