一、线程消息
在窗体应用中,线程可调用窗口过程处理属于他创建的某个窗口的消息(投递而来),此外还可以直接处理其他线程投递的消息。
(1)定义线程消息标志
线程消息可以是任意的,不必为WM_USER,当然为了获得系统范围内唯一的消息标志,也可以使用自定义的登记消息作为线程消息
UINT MYTHREADMSG = RegisterWindowMessage("MYTHREADMSG");
提示:不用static关键字修饰MYTHREADMSG 变量,使得其他CPP文件中可以使用该变量。
(2)手工修改CWindThread的消息映射表,添加线程消息映射宏
跟线程消息相关的映射宏有两个:ON_THREAD_MESSAGE和ON_REGISTERED_THREAD_MESSAGE。前者处理一般的线程消息,而后者专用于处理登记的线程消息。
#define ON_THREAD_MESSAGE(message,memberFxn)\ {message,0,0,0,AfxSig_vwl,\ (AFX_PMSG)(AFX_PMSGT)(static_cast<void (AFX_MSG_CALL CWinThread::*)(WPARAM,LPARAM)>(memberFxn))},
#define ON_REGISTERED_THREAD_MESSAGE(message,memberFxn)\ {message,0,0,0,(UINT_PTR)(UINT *)(&nMessageVariable),\ (AFX_PMSG)(AFX_PMSGT)(static_cast<void (AFX_MSG_CALL CWinThread::*)(WPARAM,LPARAM)>(memberFxn))},
从上面的定义可以看出:
a.只有CWinThread类才允许处理线程消息。
b.线程消息处理函数的签名形式为:void (WPARAM,LPARAM)
(3)实现处理线程消息的成员
void (WPARAM,LPARAM)
(4)引发线程消息。
通过调用CWinThread对象的PostThreadMessage,将线程消息投递到CWinThread对象的线程队列。
Example:
二、跨进程处理消息
进程是操作系统分配资源的基本单位。每个进程都有一个独立的地址空间,并至少拥有一个线程来执行其代码。事实上,Windows提供的消息处理机制是完全可以跨进程进行的。虽然每个进程都在独立的地址空间中运行,但是各个进程都共享一段系统分区(又称核心区),核心区将被映射到每个进程空间中,并且其位置也是固定的。操作系统在核心区放置了一些关键数据(这些数据又称核心对象),并提供了一组API函数对这些数据进行操作。而这些核心区恰好就保存了系统当前创建的所有窗口,并将每个窗口和创建它的线程关联起来。
因为由核心区的数据提供的信息,系统可以定位到任何一个窗口,从窗口出发,系统还可以找到创建该窗口的线程,然后就可以轻易的把消息放入线程的消息队列中。
(1)定位到接收消息的窗口
为了找到接收消息的窗口,可以调用FindWindow,依据窗口的类名和窗口名(也就是窗口标题)查找特定的窗口:
HWND FindWindow( LPCTSTR lpClassName, //窗口类名 LPCTSTR lpWindowName //窗口名,也就是窗口标题 );
可以将lpClassName或lpWindowName设为NULL,这时将忽略窗口类名或窗口名,仅依据一个条件进行搜索。这种方法最多只能返回一个窗口。
如果要支持查找多个窗口,可以用EnumWindow函数:
BOOL EnumWindows( WNDENUMPROC lpEnumFunc, //回调函数 LPARAM lParam //回调函数的参数 );
每当找到一个窗口,系统就会执行lpEnumFunc,其原型定义为:BOOL CALLBACK (HWND hWnd, LPARAM lParam)
参数hWnd表示当前正在枚举的窗口,lParam是由调用EnumWindows时的第二参数lParam规定的,如果希望继续枚举窗口,则返回TRUE,否则返回FALSE。在回调函数内,可以依据一定的条件判断hWnd窗口是否为目标窗口,若是,则可以向其发送消息。
提示:对于代表窗口的窗口句柄,其值在系统范围都是唯一的,这也简化了跨进程的消息通信的实现。
(2)向窗口发送消息
找到目标窗口后,就可以用SendMessage或PostMessage向其发送或投递消息。
(3)目标窗口响应消息
消息映射宏:ON_REGISTERED_MESSAGE
成员函数的签名:LRESULT (WPARAM,LPARAM)
Example: