3.线程与消息队列
在WIN32中,每一个线程都对应着一个消息队列。由于一个线程可以产生数个窗口,所以并不是每个窗口都对应着一个消息队列。下列几句话应该作为"定理"被记住:
"定理" 一
所有产生给某个窗口的消息,都先由创建这个窗口的线程处理;
"定理" 二
Windows屏幕上的每一个控件都是一个窗口,有对应的窗口函数。
消息的发送通常有两种方式,一是SendMessage,一是PostMessage,其原型分别为:
LRESULT SendMessage(HWND hWnd, // handle of destination window UINT Msg, // message to send WPARAM wParam, // first message parameter LPARAM lParam // second message parameter ); BOOL PostMessage(HWND hWnd, // handle of destination window UINT Msg, // message to post WPARAM wParam, // first message parameter LPARAM lParam // second message parameter ); |
两个函数原型中的四个参数的意义相同,但是SendMessage和PostMessage的行为有差异。SendMessage必须等待消息被处理后才返回,而PostMessage仅仅将消息放入消息队列。SendMessage的目标窗口如果属于另一个线程,则会发生线程上下文切换,等待另一线程处理完成消息。为了防止另一线程当掉,导致SendMessage永远不能返回,我们可以调用SendMessageTimeout函数:
LRESULT SendMessageTimeout( HWND hWnd, // handle of destination window UINT Msg, // message to send WPARAM wParam, // first message parameter LPARAM lParam, // second message parameter UINT fuFlags, // how to send the message UINT uTimeout, // time-out duration LPDWORD lpdwResult // return value for synchronous call ); |
4. MFC线程、消息队列与MFC程序的"生死因果"
分析MFC程序的主线程启动及消息队列处理的过程将有助于我们进一步理解UI线程与消息队列的关系,为此我们需要简单地叙述一下MFC程序的"生死因果"(侯捷:《深入浅出MFC》)。
使用VC++ 6.0的向导完成一个最简单的单文档架构MFC应用程序MFCThread:
(1) 输入MFC EXE工程名MFCThread;
(2) 选择单文档架构,不支持Document/View结构;
(3) ActiveX、3D container等其他选项都选择无。
我们来分析这个工程。下面是产生的核心源代码:
MFCThread.h 文件
class CMFCThreadApp : public CWinApp {
public: CMFCThreadApp();
// Overrides // ClassWizard generated virtual function overrides //{
{AFX_VIRTUAL(CMFCThreadApp) public: virtual BOOL InitInstance(); //}}AFX_VIRTUAL
// Implementation
public: //{
{AFX_MSG(CMFCThreadApp) afx_msg void OnAppAbout(); // NOTE - the ClassWizard will add and remove member functions here. // DO NOT EDIT what you see in these blocks of generated code ! //}}AFX_MSG DECLARE_MESSAGE_MAP() }; |
MFCThread.cpp文件
CMFCThreadApp theApp;
/ // CMFCThreadApp initialization
BOOL CMFCThreadApp::InitInstance() {
… CMainFrame* pFrame = new CMainFrame; m_pMainWnd = pFrame;
// create and load the frame with its resources pFrame->LoadFrame(IDR_MAINFRAME,WS_OVERLAPPEDWINDOW | FWS_ADDTOTITLE, NULL,NULL); // The one and only window has been initialized, so show and update it. pFrame->ShowWindow(SW_SHOW); pFrame->UpdateWindow();
return TRUE; } |
MainFrm.h文件
#include "ChildView.h"
class CMainFrame : public CFrameWnd {
public: CMainFra |