在Windows中,用户或系统中所发生的任何活动被当作事件来处理,例如,用户按下了鼠标按钮,就产生一鼠标事件。对于所发生的每一个事件,Windows将其转换成消息的形式放在一个称为消息队列的内存区中,然后由Windows的消息发送程序选择适合的对象,将消息队列中的消息发送到欲接受消息的对象上。Windows的消息可分为四种类型: 关于自定义消息的参数 自定义消息如果光是消息那只能是一个通知。 1.SendMessage函数功能描述:将指定的消息发送到一个或多个窗口。此函数为指定的窗口调用窗口过程,直到窗口过程处理完消息后才返回。 .函数原型:
case WM_KEYDOWN: switch (wParam) { case VK_HOME: SendMessage (hwnd, WM_VSCROLL, SB_TOP, 0) ; break ; case VK_END: SendMessage (hwnd, WM_VSCROLL, SB_BOTTOM, 0) ; break ; case VK_PRIOR: SendMessage (hwnd, WM_VSCROLL, SB_PAGEUP, 0) ; break ; ... } return 0 ; ...
SendMessage(hwnd, WM_COPY, 0, 0); SendMessage(hwnd, WM_CUT, 0, 0); SendMessage(hwnd, WM_PASTE, 0, 0); 2)SendMessage与PostMessage的区别 3)SendMessage发送WM_COPYDATA消息在进程间传送数据 std:string strData = "VC知识库 VCKBASE.COM"; COPYDATASTRUCT cds; cds.dwData = 0; cds.cbData = strData.Length(); cds.lpData = strData.c_str(); ::SendMessage(hwnd, WM_COPYDATA, NULL, (LPARAM)&cds); 2.SendMessageCallback
函数功能:该函数将指定的消息发送到一个或多个窗口。此函数为指定的窗口调用窗口程序,并立即返回。当窗口程序处理完消息后,系统调用指定的回调函数,将消息处理的结果和一个应用程序定义的值传给回调函数。
函数原型:BOOL SendMessageCallback(HWND hwnd,UINT Msg,WPARAM wParam,LPARAM IParam,
SEhDASYNCPROC IpResultCallBack,DWORD dwData);
参数:
hWnd:其窗口程序将接收消息的窗口的句柄。如果此参数为HWND_BROADCAST,则消息将被发送到系统中所有顶层窗口,包括无效或不可见的非自身拥有的窗口、被覆盖的窗口和弹出式窗口,但消息不被发送到子窗口。
Msg:指定被发送的消息。
wParam:指定附加的消息指定信息。
IParam:指定附加的消息指定信息。
IpResultCallBack:指向回收函数的指针,窗曰程序处理完消息后调用该回调函数。参见SendAsyncProc可得到合适的回调函数的信息。如果hwnd为HWND_BROADCAST,系统为每个顶层窗口调用一次SendASyncProc回调函数。
dwData:一个应用程序定义的值,被传给由参数IPResultCallBack指向的回调函数。
返回值:如果函数调用成功,返回非零值。如果函数调用失败,返回值是零。若想获得更多的错误信息,请调用GetLastError函数。
备注:如果发送一个低于WM_USER范围的消息给异步消息函数(PostMessage,SendNotifyMesssge;SendMessageCallback),消息参数不能包含指针。否则,操作将会失败。函数将在接收线程处理消息之前返回,发送者将在内存被使用之前释放。
需要以HWND_BROADCAST方式通信的应用程序应当用函数RegisterWindwosMessage来获得应用程序间通信的独特的消息。
此回调函数仅当调用SendMessagecallback的线程调用GetMessage,PeekMessage或WaitMessage时调用。
例如:
case WM_LBUTTONDOWN:
SendMessageCallback(hWnd,WM_LBUTTONUP,0,0,SendAsyncProc,0); //具体的回调函数实现
VOID CALLBACK SendAsyncProc(HWND hwnd,UINT uMsg,DWORD dwData,LRESULT lResult) { MessageBox(NULL,"Back From Main Window","SendMessageCallback",MB_OK); //下面可以进行更进一步的处理 } 还有这样一个例子:
在《windows高级编程指南》中说道SendMessageCallback()在发送后就立即返回。但是我在堵塞测试的时候发现,调用SendMessageCallback
的线程也死掉了, 下面是我的代码 大概就是在用SendMessageCallback发送消息给对话框之前,创建一个Event,设置为无信号,然后在 对话框的消息响应中等待Event变为有信号才继续执行,根据书上所说,SendMessageCallback()在发送会就返回, 那么发送消息的线程就应该不会因为对话框在处理消息时候因为等待Event而给堵塞住,这样发送线程就可以继续执行下面的SetEvent, 这样对话框WaitForSingleObject()得以返回,这样它也可以得以继续执行 。 void CMainFrame::OnOpendialog() { //该函数创建一个无模式对话框 CWorkingDialog* pdlg=new CWorkingDialog; ASSERT_VALID(pdlg); //Create the modeless dialog . represents this dialog. BOOL bResult = pdlg-> Create(IDD_DIALOG1); CString strMsg= "From MainFrame "; HANDLE hEvent=CreateEvent(NULL,TRUE,FALSE, "wait ");//创建事件通知 ,手动,无信号 SendMessageCallback(pdlg-> GetSafeHwnd(),WM_MSG,(WPARAM)(LPCTSTR)strMsg,0,FunCallback,0); strMsg= "Yes "; SetEvent(hEvent); } //响应wm_msg void CWorkingDialog::OnTestMsg(WPARAM wParam ,LPARAM lParam) { HANDLE hEvent = CreateEvent(NULL,TRUE,FALSE, "wait "); ASSERT(GetLastError()==ERROR_ALREADY_EXISTS); CString str((LPCTSTR)wParam); WaitForSingleObject(hEvent,INFINITE);//等到有信号才执行下面的代码 MessageBox(str); } 但是这段代码运行结果跟我上面的猜想不一致,是不是我对SendMessageCallback的“发送就返回”理解错误? 原因是对于SendMessageCallback()函数, 如果发送到当前线程中,则直接调用窗口过程,发送到其它线程中则立即返回。 3. SendNotifyMessage
函数功能:该函数将指定的消息发送到一个窗口。如果该窗口是由调用线程创建的;此函数为该窗口调用窗口程序,并等待窗口程序处理完消息后再返回。如果该窗口是由不同的线程创建的,此函数将消息传给该窗口程序,并立即返回,不等待窗口程序处理完消息。
函数原型:BOOL SendNotifyMessage(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM IParam);
参数:
hWnd:其窗口程序将接收消息的窗口的句柄。如果此参数为HWND_BROADCAST,则消息将被发送到系统中所有顶层窗口,包括无效或不可见的非自身拥有的窗口、被覆盖的窗口和弹出式窗口,但消息不被发送到子窗口。
Msg:指定被发送的消息。
wParam:指定附加的消息指定信息。
IParam:指定附加的消息指定信息。
返回值:如果函数调用成功,返回非零值;如果函数调用失败,返回值是零。若想获得更多的错误信息,请调用GetLastError函数。
备注:如果发送一个低于WM_USER范围的消息给异步消息函数(PostMessage,SendNotifyMessage,SendMesssgeCallback),消息参数不能包含指针。否则,操作将会失败。函数将在接收线程处理消息之前返回,发送者将在内存被使用之前释放。
需要以HWND_BROADCAST方式通信的应用程序应当用函数RegisterWindwosMessage来获得应用程序间通信的独特的消息。
例子:
case WM_RBUTTONDOWN:
HANDLE hThread; DWORD ThreadID; //创建一个线程,把当前的窗口句柄作为参数传递给新线程 hThread=CreateThread(NULL,0,Thread1,hWnd,NULL,&ThreadID); break; case WM_LBUTTONDOWN: MessageBox(NULL,"Receiving Message:WM_LBUTTONDOWN","MESSAGE",MB_OK); break; //具体的线程函数实现
DWORD WINAPI Thread1(LPVOID param) { HWND hWnd=(HWND)param; SendNotifyMessage(hWnd,WM_LBUTTONDOWN,0,0); //一般情况下,这个消息框要比上面那个消息框早出现,因为函数并不等待消息 //处理完成之后才返回 MessageBox(NULL,"Return From SendNotifyMessage","SendNotifyMessage",MB_OK); return 1; } 4. SendMessageTimeout
函数功能:该函数将指定的消息发送到一个或多个窗口。此函数为指定的窗口调用窗口程序,并且,如果指定的窗口属于不同的线程,直到窗口程序处理完消息或指定的超时周期结束函数才返回。如果接收消息的窗口和当前线程属于同一个队列,窗口程序立即调用,超时值无用。
函数原型:LRESULT SendMessageTimeout(HWND hwnd,UINT Msg,WPARAM wParam,LPARAM IParam,UINTfuFlags,UIUT uTimeout,LPDWORD lpdwResultult);
参数:
hWnd:其窗口程序将接收消息的窗口的句柄。如果此参数为HWND_BROADCAST,则消息将被发送到系统中所有顶层窗口,包括无效或不可见的非自身拥有的窗口。
Msg:指定被发送的消息。
wParam:指定附加的消息指定信息。
IParam:指定附加的消息指定信息。
fuFlags;指定如何发送消息。此参数可为下列值的组合:
SMTO_ABORTIFHUNG:如果接收进程处于“hung”状态,不等待超时周期结束就返回。
SMTO_BLOCK:阻止调用线程处理其他任何请求,直到函数返回。
SMTO_NORMAL:调用线程等待函数返回时,不被阻止处理其他请求。
SMTO_NOTIMEOUTIFNOTHUNG:Windows 95及更高版本:如果接收线程没被挂起,当超时周期结束时不返回。
uTimeout:为超时周期指定以毫秒为单位的持续时间。如果该消息是一个广播消息,每个窗口可使用全超时周期。例如,如果指定5秒的超时周期,有3个顶层窗回未能处理消息,可以有最多15秒的延迟。
IpdwResult:指定消息处理的结果,依赖于所发送的消息。
返回值:如果函数调用成功,返回非零值。如果函数调用失败,或超时,返回值是零。若想获得更多的错误信息,请调用GetLastError函数。如果GetLastError返回零,表明函数超时。如果使用HWND_BROADCAST,SenddMessaggTimeout不提供单个窗口超时信息。 DWORD WINAPI Thread1(LPVOID param);
case WM_RBUTTONDOWN:
HANDLE hThread; DWORD ThreadID; //创建一个线程,把当前的窗口句柄作为参数传递给新线程 hThread=CreateThread(NULL,0,Thread1,hWnd,NULL,&ThreadID); break; case WM_LBUTTONDOWN: Sleep(5000);//睡眠5秒 MessageBox(NULL,"Receving Messageg:LBUTTONDOWN","MESSAGE",MB_OK); break; DWORD WINAPI Thread1(LPVOID param)
{ HWND hWnd=(HWND)param; DWORD dwResult; LRESULT ret; //只等待三秒 ret=SendMessageTimeout(hWnd,WM_LBUTTONDOWN,0,0,SMTO_BLOCK,3000,&dwResult); if(ret==0) MessageBox(NULL,"Fail To Process Message","SendMessageTimeout",MB_OK); else MessageBox(NULL,"Success To Process Message","SendMessageTimeout",MB_OK); return 1; } 如果不 Sleep(5000);//睡眠5秒。先 MessageBox(NULL,"Receving Messageg:LBUTTONDOWN","MESSAGE",MB_OK);
后 if(ret==0);但是Sleep(5000);先 if(ret==0)后MessageBox(NULL,"Receving Messageg:LBUTTONDOWN","MESSAGE",MB_OK); 5.PostThreadMessage
函数原型:BOOL PostThreadMessage(DWORD idThread,UINT Msg,WPARAM wParam,LPARAM IParam);
参数
idThread:其消息将被寄送的线程的线程标识符。如果线程没有消息队列,此函数将失败。当线程第一次调用一个Win 32 USER或GDI函数时,系统创建线程的消息队列。要得到更多的信息,参见备注。
Msg:指定将被寄送的消息的类型。
wParam:指定附加的消息特定信息。
IParam:指定附加的消息特定信息。
返回值:如果函数调用成功,返回非零值。如果函数调用失败,返回值是零。若想获得更多的错误信息,请调用GetLastError函数。如果idThread不是一个有效的线程标识符或由idThread确定的线程没有消息队
列,GetLastError返回ERROR_INVALID_THREAD。
备注:消息将寄送到的线程必须创建消息队列,否则调用PostThreadMessage会失败。用下列方法之一来处理这种情况:
调用PostThreadMessage。如果失败,调用Sleep,再调用PostThreadMessage,反复执行,直到PostThreadMessage成功。
创建一个事件对象,再创建线程。在调用PostThreadMessage之前,用函数WaitForSingleObject来等特事件被设置为被告知状态。消息将寄送到的线程调用PeekMessage(&msg,NULL,WM_USER,WM_USER,PM_NOREMOVE)来强制系统创建消息队列。设置事件,表示线程已准备好接收寄送的消息。
消息将寄送到的线程通过调用GetMesssge或PeekMesssge来取得消息。返回的MSG结构中的hwnd成员为NULL。
case WM_RBUTTONDOWN:
HANDLE hThread; DWORD ThreadID,LocalThreadID; //将当前线程ID作为参数传递给新线程 LocalThreadID=GetCurrentThreadId(); hThread=CreateThread(NULL,0,Thread1,(LPVOID)LocalThreadID,NULL,&ThreadID); break; //具体的线程函数实现
DWORD WINAPI Thread1(LPVOID param) { DWORD MainThreadID; MainThreadID=(DWORD)param; //向主线程发送一条消息 PostThreadMessage(MainThreadID,WM_LBUTTONDOWN,0,0); return 1; } 6.函数功能:该函数将一个消息放入(寄送)到与指定窗口创建的线程相联系消息队列里,不等待线程处理消息就返回,是异步消息模式。消息队列里的消息通过调用GetMessage和PeekMessage取得。
函数原型:B00L PostMessage(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam);
参数
hWnd:其窗口程序接收消息的窗口的句柄。可取有特定含义的两个值:
HWND_BROADCAST:消息被寄送到系统的所有顶层窗口,包括无效或不可见的非自身拥有的窗口、被覆盖的窗口和弹出式窗口。消息不被寄送到子窗口。
NULL:此函数的操作和调用参数dwThread设置为当前线程的标识符PostThreadMessage函数一样。
Msg:指定被寄送的消息。
wParam:指定附加的消息特定的信息。
IParam:指定附加的消息特定的信息。
返回值:如果函数调用成功,返回非零值:如果函数调用失败,返回值是零。若想获得更多的错误信息,请调用GetLastError函数。
备注:需要以 HWND_BROADCAST方式通信的应用程序应当用函数 RegisterwindwosMessage来获得应用程序间通信的独特的消息。
如果发送一个低于WM_USER范围的消息给异步消息函数(PostMessage.SendNotifyMessage,SendMesssgeCallback),消息参数不能包含指针。否则,操作将会失败。函数将再接收线程处理消息之前返回,发送者将在内存被使用之前释放。
速查:Windows NT: 3.1及以上版本;Windows:95及以上版本;Windows CE:1.0及以上版本;头文件:winuser.h;输入库:user32.lib;Unicode:在Windows NT环境下以Unicode和ANSI方式实现。
P.S. 为什么 “如果发送一个低于WM_USER范围的消息给异步消息函数(PostMessage.SendNotifyMessage,SendMesssgeCallback),消息参数不能包含指针。否则,操作将会失败。
#define WM_SENDMESSAGE WM_USER+1
#define WM_POSTMESSAGE WM_USER+2 DWORD WINAPI Thread1(LPVOID param)
case WM_SENDMESSAGE:
MessageBox(NULL,"本对话框结束之后SendMessage才会返回!","SendMessage",MB_OK); break; case WM_POSTMESSAGE: MessageBox(NULL,"本对话框结束之前PostMessage已经返回!","SendMessage",MB_OK); break; case WM_RBUTTONDOWN: HANDLE hThread; DWORD ThreadID; //创建一个线程,将当前的窗口句柄作为参数传递给该新创建的线程 hThread=CreateThread(NULL,0,Thread1,hWnd,NULL,&ThreadID); break; //具体的线程函数实现
DWORD WINAPI Thread1(LPVOID param) { HWND hWnd; hWnd=(HWND)param; //可以比较下面两种发送消息的差别 PostMessage(hWnd,WM_POSTMESSAGE,0,0); // SendMessage(hWnd,WM_SENDMESSAGE,0,0); return 1; } 7. PostQuitMessage
函数功能:该函数向系统表明有个线程有终止请求。通常用来响应WM_DESTROY消息。
函数原型:VOID PostQuitMessage(int nExitCode);
参数:
nExitCode:指定应用程序退出代码。此值被用作消息WM_QUIT的wParam参数。
返回值:无。
备注:PostQuitMessage寄送一个WM_QUIT消息给线程的消息队列并立即返回;此函数向系统表明有个线程请求在随后的某一时间终止。
当线程从消息队列里取得WM_QUIT消息时,应当退出消息循环并将控制返回给系统。返回给系统的退出值必须是消息WM_QUIT的wParam参数。
case WM_LBUTTONDOWN:
PostQuitMessage(1); 8.BroadcastSystemMessage
该函数发送消息给指定的接受者。接受者可以是一个应用程序、安装驱动器、网络驱动器、系统级设备驱动器或这些系统组件的组合。
函数原型:long BroadcastSystemMessage(DWORD dwFIags,LPDWORD IpdwRecipients,UINT UiMessage,WPARAMwParam,LPARAM IParam);
参数: dwFlags:选项标志。可取下列值的组合:
BSF_FLUSHDISK:接受者处理消息之后清洗磁盘。
BSF_FORCEIFHUNG:继续广播消息,即使超时周期结束或一个接受者已挂起。 BSF_IGNORECURRENTTASK:不发送消息给属于当前任务的窗口。这样,应用程序就不会接收自己的消息。
BSF_NOHANG:强制挂起的应用程序超时。如果一个接受者超时,不再继续广播消息。 BSF_NOTIMEOUTIFNOTHUNG:只要接受者没挂起,一直等待对消息的响应。不会出现超时。 BSF_POSTMESSAGE:寄送消息。不能和BSF_QUERY组合使用。
BSF_QUERY:每次发送消息给一个接受者,只有当前接受者返回TRUE后,才能发送给下一个接受者。 lpdwRecipients:指向变量的指针,该变量含有和接收消息接受者的信息。此变量可为下列值的组合: BSM_ALLCOMPONENTS:广播到所有的系统组件。
BSM_ALLDESKTOPS:Windows NT下,广播到所有的桌面。要求SE_TCB_NAME特权。
BSM_APPLICATIONS:广播到应用程序。
BSM_INSTALLABLEDRIVERS:Windows 95下,广播到安装驱动器。
BSM_INTDRIVER:Windows 95下,广播到网络驱动器。
BSM_VXDS:Windows 95下,广播到所有系统级设备驱动器。
当函数返回时,此变量接受上述值的组合,以确定真正接受消息的接受者。如果此参数为NULL,则将消息广播到所有的组件。
uiMessage:系统消息标识符。
WParam:32位消息特定值。
IParam:32位消息特定值。
返回值:如果函数调用成功,返回值是正数。如果函数不能广播消息,返回值是C1。如果参数dwFlags为BSF_QUERY且至少一个接受者返回BROADCAST_QUERY_DENY给相应的消息,返回值是零。若想获得更多的错误信息,请调用GetLastError函数。 备注:如果BSF_QUERY没指定,函数发送指定的消息给所有请求的接受者,并忽略这些接受者返回的值。
RegisterWindowMessage中的BroadcastSystemMessage如何处理 我想用BroadcastSystemMessage来在两个进程之间通讯,我从一个进程发送了一个用 RegisterWindowMessage注册过的消息,但在目的进程中却没有收到该消息. A:我认为你应该在两个进程的最高级窗口中都注册该消息.请看下例: static UINT sBroadcastCommand = ::RegisterWindowMessage( _T("BroadcastCommand")); BEGIN_MESSAGE_MAP( Gui_Top_Level_MainFrame, Gui_MainFrame ) ON_REGISTERED_MESSAGE( sBroadcastCommand, onBroadcastCommand ) END_MESSAGE_MAP() LRESULT Gui_MainFrame :: onBroadcastCommand( UINT aMsg, LPARAM lParam ) { your code... }然后发送进行应该包含: While the sending process would contain: static UINT sBroadcastCommand = ::RegisterWindowMessage( _T("BroadcastCommand")); void Someclass :: someMethod( void ) { ::PostMessage( (HWND)HWND_BROADCAST,sBroadcastCommand, 0,yourMessageId ); } 9.ReplyMessage 函数功能:该函数用于应答由函数SendMessage发送的消息,不返回控制给调用SendMessage的函数。 函数原型:BOOL ReplyMessage(LRESULTIResult); 参数: IResult:指定消息处理的结果。可能的值由所发送的消息确定。 返回值:如果调用线程正处理从其他线程或进程发送的消息,返回非零值。如果调用线程不是正处理从其他线程或进程发送的消息,返回值是零。 备注:调用此函数,接收消息的窗口程序允许调用SendMessage的线程继续运行,尽管接收消息的线程已返回控制。调用ReplyMessage的线程也继续运行。 如果消息不是通过SendMessage发送的,或者消息由同一个线程发送,ReplyMessage不起作用。 case WM_LBUTTONDOWN: //具体的线程函数实现 while (WaitMessage()) 10. WM_NOTIF在WIN32中得到大量的应用,同时也是随着CommControl的出现WM_NOTIFY成为了CommControl的基本消息。可以这样说CommControl的所有的新增特性都通过WM_NOTIFY来表达。同时WM_NOTIFY也为CommControl的操作带来了一致性。
|
|