关于MFC 消息映射机制剖析Word文件下载.docx
- 文档编号:18237946
- 上传时间:2022-12-14
- 格式:DOCX
- 页数:15
- 大小:27.93KB
关于MFC 消息映射机制剖析Word文件下载.docx
《关于MFC 消息映射机制剖析Word文件下载.docx》由会员分享,可在线阅读,更多相关《关于MFC 消息映射机制剖析Word文件下载.docx(15页珍藏版)》请在冰豆网上搜索。
goto
InitFailure;
11.}
12.
Run();
//
进入消息循环
执行CWinApp:
:
Run():
Main
running
routine
until
application
exits
2.int
CWinApp:
Run()
(m_pMainWnd
==
NULL
&
AfxOleGetUserCtrl())
Not
launched
/Embedding
or
/Automation,
but
has
no
main
window!
is
in
Run
-
quitting
application.\n"
AfxPostQuitMessage(0);
return
CWinThread:
执行CWinThread:
Run():
thread
ASSERT_VALID(this);
_AFX_THREAD_STATE*
pState
AfxGetThreadState();
for
tracking
the
idle
time
state
BOOL
bIdle
TRUE;
LONG
lIdleCount
0;
11.
acquire
and
dispatch
messages
a
WM_QUIT
message
received.
12.GetMessage:
从系统获取消息,将消息从系统中移除,属于阻塞函数。
当系统无消息时,GetMessage会等待下一条消息。
而函数PeekMesssge是以查看的方式从系统中获取消息,可以不将消息从系统中移除,是非阻塞函数;
当系统无消息时,返回FALSE,继续执行后续代码
13.
(;
;
)
14.
15.
phase1:
check
to
see
we
can
do
work
16.
while
(bIdle
17.
PeekMessage(&
(pState->
m_msgCur),
NULL,
PM_NOREMOVE))
18.
19.
call
OnIdle
20.
OnIdle(lIdleCount++))
21.
FALSE;
assume
idle"
22.
23.
24.
phase2:
pump
available
25.
26.
27.
message,
quit
on
28.
PumpMessage())
29.
30.
31.
reset
after
pumping
normal"
32.
//if
(IsIdleMessage(&
m_msgCur))
33.
m_msgCur)))
34.
35.
36.
37.
38.
39.
(:
PM_NOREMOVE));
//查看消息队列中是否有消息
40.
41.}
在do-while循环中进行消息的路由,主要函数就是
PumpMessage(),我们跟着进入这个函数看看做了什么:
1.BOOL
PumpMessage()
2.{
3.
AfxInternalPumpMessage();
4.}
继续跟踪:
AFXAPI
AfxInternalPumpMessage()
_AFX_THREAD_STATE
*pState
GetMessage(&
NULL))//
从消息队列获取消息
7.#ifdef
_DEBUG
1,
PumpMessage
Received
WM_QUIT.\n"
pState->
m_nDisablePumpCount++;
must
die
10.#endif
Note:
prevents
calling
loop
things
'
ExitInstance'
12.
will
never
be
decremented
16.#ifdef
m_nDisablePumpCount
0)
Error:
called
when
not
permitted.\n"
ASSERT(FALSE);
22.#endif
24.#ifdef
_AfxTraceMsg(_T("
PumpMessage"
),
m_msgCur));
26.#endif
process
this
30.
m_msgCur.message
WM_KICKIDLE
AfxPreTranslateMessage(&
32.:
TranslateMessage(&
33.:
DispatchMessage(&
36.}
从上面的代码我们可以看到MFC是通过
GetMessage()来获取消息,然后再看下面这几句代码:
1.if
5.}
也就是说当系统获取消息后,先调用
AfxPreTranslateMessage()这个看起来跟我们经常看到的PreTranslateMessage()很像!
我们来看看到底发生了什么:
__cdecl
AfxPreTranslateMessage(MSG*
pMsg)
CWinThread
*pThread
AfxGetThread();
if(
pThread
PreTranslateMessage(
pMsg
else
AfxInternalPreTranslateMessage(
8.}
执行
PreTranslateMessage():
PreTranslateMessage(MSG*
执行AfxInternalPreTranslateMessage():
AfxInternalPreTranslateMessage(MSG*
3.//
thread-message,
short-circuit
function
(pMsg->
hwnd
DispatchThreadMessageEx(pMsg))
walk
from
target
window
CWnd*
pMainWnd
AfxGetMainWnd();
(CWnd:
WalkPreTranslateTree(pMainWnd->
GetSafeHwnd(),
pMsg))//
注意这个函数
case
of
modeless
dialogs,
last
chance
route
through
window'
s
accelerator
table
(pMainWnd
pWnd
CWnd:
FromHandle(pMsg->
hwnd);
(pWnd->
GetTopLevelParent()
pMainWnd)
pMainWnd->
PreTranslateMessage(pMsg);
special
processing
28.}
执行CWnd:
GetSafeHwnd(),pMsg)
PASCAL
WalkPreTranslateTree(HWND
hWndStop,
MSG*
ASSERT(hWndStop
||
IsWindow(hWndStop));
ASSERT(pMsg
NULL);
up
hWndStop
checking
any
wants
translate
(HWND
hWnd
pMsg->
hwnd;
NULL;
GetParent(hWnd))
FromHandlePermanent(hWnd);
(pWnd
C++
PreTranslateMessage(pMsg))
trapped
by
(eg:
accelerators)
got
without
interest
(hWnd
hWndStop)
break;
24.}
MFC在后台维护了一个句柄和C++对象指针的映射表,一旦有消息产生时,我们知道这个消息的结构体中包含了该消息所属窗口的句柄,那么通过这个句柄我们可以找到相对于的C++对象的指针,在for循环里面遍历当前窗口的所有父窗口,查找是否有消息重写,一旦有子类重写父类消息的,则通过当前消息所属窗口的句柄来调用CWnd:
FromHandlePermanent(hWnd)
函数,从而得到当前C++对象的指针,最后调用PreTranslateMessage(),因为
PreTranslateMessage()是虚函数,所以调用的是子类的
PreTranslateMessage(),该函数可以自定义一部分消息的处理方式。
需要注意的是,PreTranslateMessage()返回为FALSE时,说明没有发生消息的重写,则把消息直接给
TranslateMessage()和DispatchMessage()进行处理,当返回是TRUE时,则去消息队列获取下一条消息。
另外,SendMessage()是直接发送给WindowProc进行处理(该函数是一个DispatchMessage()中的一个回调函数,用于处理默认的一些系统消息),没有进入消息队列,所以不会被GetMessage()抓取到,所以也就不会PreTranslateMessage()抓到了,但是PostMessage()是进入消息队列的,是可以被GetMessage()抓到的。
所以从上面的代码跟踪可见,当我们需要重写一些系统消息时,比如给程序设置一些快捷键等,可以在PreTranslateMessage()中进行操作,当然,不是PreTranslateMessage()并不是可以重写所有消息,有一些消息也是无法处理的,这时可以交给WindowProc进行处理,WindowProc()也是虚函数。
1.LRESULT
WindowProc(UINT
WPARAM
wParam,
LPARAM
lParam)
OnWndMsg
does
most
work,
except
DefWindowProc
LRESULT
lResult
5.
OnWndMsg(message,
lParam,
lResult))
DefWindowProc(message,
lParam);
lResult;
消息的映射主要是通过OnWndMsg()进行处理,考虑到该函数代码很多,就不全贴了,我们分析其中一小段:
1.for
(/*
pMessageMap
already
init'
ed
*/;
pMessageMap->
pfnGetBaseMap
2.
(*pMessageMap->
pfnGetBaseMap)())
catch
so
common
fatal
mistake!
BEGIN_MESSAGE_MAP(CMyWnd,
CMyWnd)
ASSERT(pMessageMap
pfnGetBaseMap)());
(message
<
0xC000)
constant
((lpEntry
AfxFindMessageEntry(pMessageMap->
lpEntries,
0))
pMsgCache->
lpEntry
lpEntry;
winMsgLock.Unlock();
LDispatch;
registered
windows
lpEntries;
AfxFindMessageEntry(lpEntry,
0xC000,
UINT*
pnID
(UINT*)(lpEntry->
nSig);
ASSERT(*pnID
>
0xC000
*pnID
0);
successfully
(*pnID
message)
LDispatchRegistered;
lpEntry++;
keep
looking
past
one
在for循环里面有这样一个数据:
AFX_MSGMAP*
pMessageMap(),它代表当前C++对象的消息映射表指针,那么这里的消息映射表到底是个什么样的数据结构,我们来一探究竟。
我们打开
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 关于MFC 消息映射机制剖析 关于 MFC 消息 映射 机制 剖析