转MFC消息映射梳理
http://blog.csdn.net/phunxm/article/details/5640766
一.CWnd消息处理
一切从窗口(HWND)的创建说起,在MFC中,CWnd::CreateEx执行窗口创建过程。
从调用BOOL CWnd::Attach(HWND hWndNew)那一刻起,即将一个窗口(HWND)托付给一个具体的CWnd对象(子类化)。
BOOL CWnd::CreateEx(DWORD dwExStyle, LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, int x, int y, int nWidth, int nHeight, HWND hWndParent, HMENU nIDorHMenu, LPVOID lpParam)
{
// allow modification of several common create parameters
CREATESTRUCT cs;
cs.dwExStyle = dwExStyle;
cs.lpszClass = lpszClassName;
cs.lpszName = lpszWindowName;
cs.style = dwStyle;
cs.x = x;
cs.y = y;
cs.cx = nWidth;
cs.cy = nHeight;
cs.hwndParent = hWndParent;
cs.hMenu = nIDorHMenu;
cs.hInstance = AfxGetInstanceHandle();
cs.lpCreateParams = lpParam;
if (!PreCreateWindow(cs))
{
PostNcDestroy();
return FALSE;
}
AfxHookWindowCreate(this);
HWND hWnd = ::CreateWindowEx(cs.dwExStyle, cs.lpszClass, cs.lpszName, cs.style, cs.x, cs.y, cs.cx, cs.cy, cs.hwndParent, cs.hMenu, cs.hInstance, cs.lpCreateParams);
#ifdef _DEBUG
if (hWnd == NULL)
{
TRACE1("Warning: Window creation failed: GetLastError returns 0x%8.8X/n", GetLastError());
}
#endif
if (!AfxUnhookWindowCreate())
PostNcDestroy(); // cleanup if CreateWindowEx fails too soon
if (hWnd == NULL)
return FALSE;
ASSERT(hWnd == m_hWnd); // should have been set in send msg hook
return TRUE;
}
在PreCreateWindow之后,::CreateWindowEx之前,AfxHookWindowCreate函数中::SetWindowsHookEx(WH_CBT,_AfxCbtFilterHook, NULL, ::GetCurrentThreadId());安装钩子。钩子函数_AfxCbtFilterHook中调用::SetWindowLong(hWnd, GWL_WNDPROC, (DWORD)afxWndProc);将创建hWnd时所使用的WNDCLASS窗口模板的过程函数由DefWindowProc更改为AfxWndProc。
// The WndProc for all CWnd's and derived classes
LRESULT CALLBACK AfxWndProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam)
{
// ……
// all other messages route through message map
CWnd* pWnd = CWnd::FromHandlePermanent(hWnd);
// ……
return AfxCallWndProc(pWnd, hWnd, nMsg, wParam, lParam);
}
窗口函数AfxWndProc从AFX_MODULE_THREAD_STATE::m_pmapHWND中查询hWnd对应的CWnd对象,AfxCallWndProc将消息委托给具体窗口对象的WindowProc函数处理。
LRESULT AFXAPI AfxCallWndProc(CWnd* pWnd, HWND hWnd, UINT nMsg, WPARAM wParam = 0, LPARAM lParam = 0)
{
// ……
// delegate to object's WindowProc
lResult = pWnd->WindowProc(nMsg, wParam, lParam);
// ……
}
WindowProc函数调用OnWndMsg函数。
LRESULT CWnd::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
// OnWndMsg does most of the work, except for DefWindowProc call
LRESULT lResult = 0;
if (!OnWndMsg(message, wParam, lParam, &lResult))
lResult = DefWindowProc(message, wParam, lParam);
return lResult;
}
在OnWndMsg中,对消息进行分流处理:
(1)WM_COMMANDàOnCommand
// AFXMSG_.H
#define ON_COMMAND(id, memberFxn) /
{ WM_COMMAND, CN_COMMAND, (WORD)id, (WORD)id, AfxSig_vv, (AFX_PMSG)&memberFxn },
(2)WM_NOTIFYàOnNotify
// AFXMSG_.H
#define ON_NOTIFY(wNotifyCode, id, memberFxn) /
{ WM_NOTIFY, (WORD)(int)wNotifyCode, (WORD)id, (WORD)id, AfxSig_vNMHDRpl, /
(AFX_PMSG)(void (AFX_MSG_CALL CCmdTarget::*)(NMHDR*, LRESULT*))&memberFxn },
(3)WM_ACTIVATE消息特殊处理(special case for activation)
(4)WM_SETCURSOR消息特殊处理(special case for set cursor HTERROR)
(5)对于常规窗口消息,OnWndMsg调用GetMessageMap()函数获得DECLARE_MESSAGE_MAP声明的消息映射表AFX_MSGMAP,根据nMessage和nCode调用AfxFindMessageEntry函数从消息映射表中查找AFX_MSGMAP_ENTRY,根据函数签名nSig从MessageMapFunctions中查询正确的函数指针,完成消息函数(AFX_PMSG pfn)的正确调用。
BOOL CWnd::OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult)
{
LRESULT lResult = 0;
// special case for commands
if (message == WM_COMMAND)
{
if (OnCommand(wParam, lParam)) // virtual
{
lResult = 1;
goto LReturnTrue;
}
return FALSE;
}
// special case for notifies
if (message == WM_NOTIFY)
{
NMHDR* pNMHDR = (NMHDR*)lParam;
if (pNMHDR->hwndFrom != NULL && OnNotify(wParam, lParam, &lResult)) // virtual
goto LReturnTrue;
return FALSE;
}
// special case for activation
// special case for set cursor HTERROR
const AFX_MSGMAP* pMessageMap; pMessageMap = GetMessageMap();
// ……
LReturnTrue:
if (pResult != NULL)
*pResult = lResult;
return TRUE;
// ……
}
如果OnWndMsg函数对消息进行了处理,则返回TRUE,否则WindowProc中调用DefWindowProc对消息进行默认处理。
二.WM_COMMAND消息和WM_NOTIFY消息
消息是根据窗口进行分发的,而不考虑该窗口的从属关系。也就是说在子窗口中产生的消息只在子窗口函数中处理,处理完后不会再把消息传递给父窗口。父子窗口若要对某一事件做协同处理,需要做相应的通知消息反射。
class CWnd : public CCmdTarget
{
// ……
protected:
virtual BOOL OnCommand(WPARAM wParam, LPARAM lParam);
virtual BOOL OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult);
// ……
}
OnCommand函数为对子窗口控件的WM_COMMAND命令通知消息的响应;OnNotify函数为对通用控件的WM_NOTIFY通知消息的响应。
1.子窗口控件的WM_COMMAND消息
(1)子窗口控件的WM_COMMAND消息
Windows自定义的子窗口控件(Predefined Chilld Window Controls)包括BUTTON、COMBOBOX、EDIT、LISTBOX、RichEdit、SCROLLBAR、STATIC。
以上Windows预定义的子窗口控件的窗口过程中做了反射处理,即在某一事件(点击菜单,点击加速键,点击子窗口按钮,点击工具栏按钮)处理后发送一个WM_COMMAND通知消息给父窗口。这样某个事件发生了,子窗口做默认处理后,父窗口可以做后续处理使父子窗口工作协调。例如按下按钮,按钮呈凹陷状,这是由BtnProc对WM_LBUTTONDOWN(WM_PAINT)的重绘处理;松开按钮,按钮恢复原态,这是由BtnProc对WM_LBUTTONUP(WM_PAINT)的重绘处理。往往在松开按钮的时候,发送WM_COMMAND消息(消息码为BN_CLICKED)给父窗口,由父窗口做点击事件响应,这样便于状态和逻辑的分离。
The BN_CLICKED notification code is sent when the user clicks a button.
The parent window of the button receives the BN_CLICKED notification code through the WM_COMMAND message. ——MSDN
预定义BUTTON窗口类的过程函数BtnProc的处理流程大概如下:
LRESULT CALLBACK BtnProc(HWND hWnd, UINT nMessage, WPARAM wParam, LPARAM lParam)
{
switch (nMessage)
{
case WM_LBUTTONDOWN:
{
// repaint(凹陷)
RECT rc;
GetClientRect(hWnd, &rc);
InvalidateRect(hWnd, rc, TRUE);
// ……
}
break;
case WM_LBUTTONUP:
{
// repaint(复原)
RECT rc;
GetClientRect(hWnd, &rc);
InvalidateRect(hWnd, rc, TRUE);
// notify parent click event(IDC_BTN在调用::CreateWindowEx时指定)
// LONG IDC_BTN = GetWindowLong(hWnd, GWL_ID);
PostMessage(GetParent(hWnd), WM_COMMAND, MAKEWPARAM(IDC_BTN, BN_CLICKED), (LPARAM)hWnd);
// ……
}
break;
// ……
default:
DefWindowProc(hWnd, nMessage, wParam, lParam);
}
}
(2)WM_COMMAND消息的处理逻辑(子先父后)
父窗口的OnCommand函数响应子窗口控件(Chilld Window Controls)发送来的命令消息,相当于传统窗口过程中对WM_COMMAND消息按ID(LOWORD(wParam))进行分类处理。其中HIWORD(wParam)为命令通知码,lParam参数为子窗口控件的句柄。
// CWnd command handling
BOOL CWnd::OnCommand(WPARAM wParam, LPARAM lParam)
// return TRUE if command invocation was attempted
{
UINT nID = LOWORD(wParam);
HWND hWndCtrl = (HWND)lParam;
int nCode = HIWORD(wParam);
// default routing for command messages (through closure table)
if (hWndCtrl == NULL)
{
// zero IDs for normal commands are not allowed
if (nID == 0)
return FALSE;
// make sure command has not become disabled before routing
CTestCmdUI state;
state.m_nID = nID;
OnCmdMsg(nID, CN_UPDATE_COMMAND_UI, &state, NULL);
if (!state.m_bEnabled)
{
TRACE1("Warning: not executing disabled command %d/n", nID);
return TRUE;
}
// menu or accelerator
nCode = CN_COMMAND;
}
else // 着重看以下分支!
{
// control notification
ASSERT(nID == 0 || ::IsWindow(hWndCtrl));
if (_afxThreadState->m_hLockoutNotifyWindow == m_hWnd)
return TRUE; // locked out - ignore control notification
// reflect notification to child window control
if (ReflectLastMsg(hWndCtrl))
return TRUE; // eaten by child
// zero IDs for normal commands are not allowed
if (nID == 0)
return FALSE;
}
#ifdef _DEBUG
if (nCode < 0 && nCode != (int)0x8000)
TRACE1("Implementation Warning: control notification = $%X./n",
nCode);
#endif
return OnCmdMsg(nID, nCode, NULL, NULL);
}
OnCommand中优先将消息交给子窗口控件自身处理ReflectLastMsg(reflect notification to child window control)。如果子控件做了处理,那么ReflectLastMsg返回TRUE,OnCommand返回TRUE,OnWndMsg返回TRUE,参数*pResult = lResult = 1。若子控件未做处理,则交由父窗口的OnCmdMsg函数处理,OnCmdMsg从父窗口消息映射表中查找相应通知消息的处理入口。
ReflectLastMsg函数先查找到子窗口hWndChild对应的CWnd窗口对象,然后调用子窗口对象的SendChildNotifyLastMsg函数。
BOOL PASCAL CWnd::ReflectLastMsg(HWND hWndChild, LRESULT* pResult)
{
// get the map, and if no map, then this message does not need reflection
CHandleMap* pMap = afxMapHWND();
if (pMap == NULL)
return FALSE;
// check if in permanent map, if it is reflect it (could be OLE control)
CWnd* pWnd = (CWnd*)pMap->LookupPermanent(hWndChild);
ASSERT(pWnd == NULL || pWnd->m_hWnd == hWndChild);
if (pWnd == NULL)
{
//!_AFX_NO_OCC_SUPPORT
}
// only OLE controls and permanent windows will get reflected msgs
ASSERT(pWnd != NULL);
return pWnd->SendChildNotifyLastMsg(pResult);
}
SendChildNotifyLastMsg函数调用OnChildNotify函数。
BOOL CWnd::SendChildNotifyLastMsg(LRESULT* pResult)
{
_AFX_THREAD_STATE* pThreadState = _afxThreadState.GetData();
return OnChildNotify(pThreadState->m_lastSentMsg.message, pThreadState->m_lastSentMsg.wParam, ThreadState->m_lastSentMsg.lParam, pResult);
}
OnChildNotify函数调用ReflectChildNotify函数。
BOOL CWnd::OnChildNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT* pResult)
{
// first forward raw OCM_ messages to OLE control sources
// ……
return ReflectChildNotify(uMsg, wParam, lParam, pResult);
}
ReflectChildNotify函数调用OnCmdMsg。
BOOL CWnd::ReflectChildNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT* pResult)
{
// Note: reflected messages are send directly to CWnd::OnWndMsg and CWnd::OnCmdMsg for speed and because these messages are not routed by normal OnCmdMsg routing (they are only dispatched)
switch (uMsg)
{
// normal messages (just wParam, lParam through OnWndMsg)
// ……
// reflect the message through the message map as WM_REFLECT_BASE+uMsg
return CWnd::OnWndMsg(WM_REFLECT_BASE+uMsg, wParam, lParam, pResult);
// special case for WM_COMMAND
case WM_COMMAND:
{
// reflect the message through the message map as OCM_COMMAND
int nCode = HIWORD(wParam);
if (CWnd::OnCmdMsg(0, MAKELONG(nCode, WM_REFLECT_BASE+WM_COMMAND), NULL, NULL))
{
if (pResult != NULL)
*pResult = 1;
return TRUE;
}
}
break;
// special case for WM_NOTIFY
case WM_NOTIFY:
{
// reflect the message through the message map as OCM_NOTIFY
NMHDR* pNMHDR = (NMHDR*)lParam;
int nCode = pNMHDR->code;
AFX_NOTIFY notify;
notify.pResult = pResult;
notify.pNMHDR = pNMHDR;
return CWnd::OnCmdMsg(0, MAKELONG(nCode, WM_REFLECT_BASE+WM_NOTIFY), ¬ify, NULL);
}
// other special cases (WM_CTLCOLOR family)
default:
// ……
break;
}
return FALSE; // let the parent handle it
}
如果子窗口OnCmdMsg做了处理(即子窗口的AFX_MSGMAP_ENTRY中有对该WM_COMMAND消息的处理),则ReflectChildNotify函数、OnChildNotify函数、SendChildNotifyLastMsg函数、ReflectLastMsg函数返回TRUE,*pResult = 1。
如果子窗口OnCmdMsg未做处理(即子窗口的AFX_MSGMAP_ENTRY中没有对该WM_COMMAND消息的处理),则ReflectChildNotify函数、OnChildNotify函数、SendChildNotifyLastMsg函数、ReflectLastMsg函数返回FALSE,*pResult = 0。此时,父窗口的OnCommand中ReflectLastMsg(hWndCtrl)返回FALSE,消息流向父窗口的OnCmdMsg,在父窗口的AFX_MSGMAP_ENTRY中查找对该WM_COMMAND消息的处理。
(3)WM_COMMAND消息的最终归宿(CWnd::OnCmdMsgàCCmdTarget::OnCmdMsgà_AfxDispatchCmdMsgàAfxFindMessageEntry)
CWnd::OnCmdMsg是个继承自CCmdTarget的虚函数,由于CWnd并未对该函数进行覆写(CWnd的派生类CDialog、CFrameWnd、CView、CDocument等对其覆盖),故其最终流向CCmdTarget::OnCmdMsg,其主要完成消息路由,核心代码如下。
BOOL CCmdTarget::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo)
{
// ……
for (pMessageMap = GetMessageMap(); pMessageMap != NULL;
pMessageMap = pMessageMap->pBaseMap)
{
lpEntry = AfxFindMessageEntry(pMessageMap->lpEntries, nMsg, nCode, nID);
if (lpEntry != NULL)
{
// found it
// ……
return _AfxDispatchCmdMsg(this, nID, nCode,
lpEntry->pfn, pExtra, lpEntry->nSig, pHandlerInfo);
}
}
return FALSE; // not handled
}
CCmdTarget::OnCmdMsg从当前窗口(this)至具备命令消息处理的终极归属CCmdTarget根据消息号(nID)和消息码(nCode)遍历查找相应通知消息的处理入口:
for (;;) lpEntry = AfxFindMessageEntry(,,,);
若找到了消息映射,则调用_AfxDispatchCmdMsg(this,,,,,,),其中根据函数签名(lpEntry->nSig),调用(this->*lpEntry->pfn)(*)完成最终的消息处理。注意,这里通过this既可以是对当前对象覆盖的调用,也可能是对直接从基类继承的调用。
(4)常用子窗口控件的WM_COMMAND消息映射宏格式举例
CWnd对菜单的WM_COMMAND通知消息的处理,直接使用ON_COMMAND (id, memberFxn)宏进行映射。对子窗口控件的WM_COMMAND通知消息按照控件ID和消息通知码,进行了分类定义。使用ON_CONTROL(wNotifyCode, id, memberFxn)宏映射一个函数到一个定制控件通知消息。其中,定制控件通知消息是从一个控件发送到其父窗口的消息。ON_COMMAND(id, OnFoo) is the same as ON_CONTROL(0, id, OnFoo)。
例如对按钮通知消息BN(Button Notification),父窗口的消息映射中以宏ON_BN_CLICKED(id, memberFxn)来定义该窗口对按钮子控件的点击事件BN_CLICKED的响应为memberFxn。
#define ON_BN_CLICKED(id, memberFxn) /
ON_CONTROL(BN_CLICKED, id, memberFxn)
类似的,对ComboBox的通知消息CBN(ComboBox Notification),父窗口的消息映射中以宏ON_CBN_SELCHANGE(id, memberFxn)来定义该窗口对ComboBox子控件的选项改变事件CBN_SELCHANGE的响应为memberFxn。
#define ON_CBN_SELCHANGE(id, memberFxn) /
ON_CONTROL(CBN_SELCHANGE, id, memberFxn)
Static对应的通知消息STN(Static Notification),对应消息映射宏为ON_STN_*。
#define ON_STN_CLICKED(id, memberFxn) /
ON_CONTROL(STN_CLICKED, id, memberFxn)
Edit对应的通知消息EN(Edit Notification),对应消息映射宏为ON_EN_*。
#define ON_EN_SETFOCUS(id, memberFxn) /
ON_CONTROL(EN_SETFOCUS, id, memberFxn)
ListBox对应的通知消息LBN (ListBox Notification) ,对应消息映射宏为ON_LBN_*。
#define ON_LBN_SELCANCEL(id, memberFxn) /
ON_CONTROL(LBN_SELCANCEL, id, memberFxn)
2.通用控件的WM_NOTIFY消息
(1)通用控件的WM_NOTIFY消息处理流程
常用的通用控件(Common Controls)包括ToolBar、Tooltip、Status Bar、Tree View、List View、Animation、Header、Hot-Key、Progress Bar、Up-down、Tab等,它们是增强型子窗口控件,由comctrl32.dll实现。
OnNotify函数完成通用控件的通知消息处理,相当于传统窗口过程中对WM_NOTIFY消息按ID(identifier)、消息码(notification code)进行处理。一般LOWORD(wParam)为控件ID,HIWORD(wParam)为通知码(notification code),lParam参数为NMHDR*(Notify Message HeaDeR)。
BOOL CWnd::OnNotify(WPARAM, LPARAM lParam, LRESULT* pResult)
{
ASSERT(pResult != NULL);
NMHDR* pNMHDR = (NMHDR*)lParam;
HWND hWndCtrl = pNMHDR->hwndFrom;
// get the child ID from the window itself
UINT nID = _AfxGetDlgCtrlID(hWndCtrl);
int nCode = pNMHDR->code;
ASSERT(hWndCtrl != NULL);
ASSERT(::IsWindow(hWndCtrl));
if (_afxThreadState->m_hLockoutNotifyWindow == m_hWnd)
return TRUE; // locked out - ignore control notification
// reflect notification to child window control
if (ReflectLastMsg(hWndCtrl, pResult))
return TRUE; // eaten by child
AFX_NOTIFY notify;
notify.pResult = pResult;
notify.pNMHDR = pNMHDR;
return OnCmdMsg(nID, MAKELONG(nCode, WM_NOTIFY), ¬ify, NULL);
}
OnNotify中优先将消息交给通用控件自身处理ReflectLastMsg(reflect notification to child window control)。如果子控件做了处理,那么ReflectLastMsg返回TRUE,OnCommand返回TRUE,OnWndMsg返回TRUE,参数*pResult = lResult = 1。若子控件未做处理,则交由父窗口的OnCmdMsg函数处理,OnCmdMsg从父窗口消息映射表中查找相应通知消息的处理入口。
ReflectLastMsg后面的调用流程同OnCommand。
(2)常用通用控件的WM_NOTIFY消息映射宏格式举例
对通用控件的WM_NOTIFY消息,直接使用ON_NOTIFY(wNotifyCode, id, memberFxn)对ID号为id的通知码为wNotifyCode的通知消息进行映射。
例如对于树控件IDC_TREECTRL树的选项改变事件(TVN_SELCHANGED)的消息映射如下:
ON_NOTIFY(TVN_SELCHANGED, IDC_TREECTRL, OnSelChangedTreeCtrl)
(3)通用控件的WM_NOTIFY消息反射
ON_NOTIFY不反射消息。如果自己处理不了,就传给上级窗口;如果再处理不了,再往上传。实在处理不了,由框架默认处理。
ON_NOTIFY_REFLECT反射消息,把消息传给上级窗口处理,如果上级都处理不了,再反射回来自己处理。这就是MFC强大的消息反射机制。
ON_NOTIFY_REFLECT是处理消息的手段,控件传递给父窗体的普通的消息都是由父窗体函数来处理。但由ON_NOTIFY_REFLECT映射的消息先由该控件处理,如果该控件没有处理函数再发往父窗体处理。
ON_NOTIFY_REFLECT_EX映射的处理函数(OnNotify),如果返回值(LRESULT* pResult)为1,则父窗体不进行处理;如果返回值为0,则控件处理完后,父窗体也进行处理。
转MFC消息映射梳理相关推荐
- 【MFC系列-第9天】MFC消息映射机制的原理
关注公号[逆向通信猿]更精彩!!! 第9天 MFC消息映射机制的原理 9.1 对话框常用的回调函数 a)窗口创建时的消息和虚函数包括:WM_CREATE,WM_INITDIALOG,和PreSubcl ...
- MFC消息映射与消息传递内幕
MFC消息映射与消息传递内幕 Windows操作系统是以消息为基础,事件驱动的.作为程序员了解操作系统的消息传递机制是非常必要的.Microsoft的MFC有它自己的一套支持Windows操作系统消息 ...
- 用MFC消息映射机制自定义消息
Windows系统中的程序大部分都是通过消息和事件驱动的.在windows下的应用程序主要工作是进行消息的循环处理,通过循环等待消息的到来和事件的发生,然后对不同的消息和事件运行相关的代码,完成相应的 ...
- VC++/MFC消息映射机制(1):MFC消息映射原理
VC++/MFC消息映射机制(1):模仿MFC的消息映射原理 本文为原创文章,转载请注明出处,或注明转载自"黄邦勇帅(原名:黄勇) <C++语法详解>网盘地址:https://p ...
- MFC消息映射与命令传递
独酌逸醉(博客搬至http://www.perfect-is-shit.com/,本博不再更新!) Keep It Simple,Stupid! 博客园 首页 博问 闪存 联系 管理 随笔-63 文 ...
- 【转】MFC消息映射详解(整理转载)
消息:主要指由用户操作而向应用程序发出的信息,也包括操作系统内部产生的消息.例如,单击鼠标左按钮,windows将产WM_LBUTTONDOWN消息,而释放鼠标左按钮将产生WM_LBUTTONUP消息 ...
- 【MFC】MFC消息映射(二)
00. 目录 文章目录 00. 目录 01. 概述 02. 消息映射宏 2.1 BEGIN_MESSAGE_MAP 2.2 DECLARE_MESSAGE_MAP 2.3 END_MESSAGE_MA ...
- MFc消息映射机制理解
何谓消息.消息处理函数.消息映射? 消息简单的说就是指通过输入设备向程序发出指令要执行某个操作.具体的某个操作是你的一系列代码.称为消息处理函数.在SDK中消息其实非常容易理解,当窗口建立后便会有一个 ...
- MFC消息映射机制概述
消息 窗口消息一般由三个部分组成: 1)一个无符号整数,是消息值: 2)消息附带的 WPARAM 类型的参数: 3)消息附带的 LPARAM 类型的参数.其实我们一般所说的消息是狭义上的消息值,也就是 ...
最新文章
- 意外收获字节跳动内部资料,Android岗
- Linux下VNC配置多个桌面和修改密码 不会当系统重启vnc失效
- vs2005添加live555工程
- php mod11 10公式,mod运算规则
- Silverlight 2.5D RPG游戏技巧与特效处理:(十六)动态资源
- win7 nginx mysql php_windows7配置Nginx+php+mysql的详细教程
- linux文件大小和目录,查看Linux目录和文件大小
- php处理文件属性函数,文件属性 · PHP文件系统操作常用函数整理 · 看云
- 基于椭圆-最大边缘准则学习的小麦叶片病害及其严重程度识别
- 机器人技术与人工智能有什么区别?
- 【leetcode】最强边界条件
- 6. Controller
- 使用systemd来构建你的服务
- 管螺纹如何标注_【专业知识】一次搞全所有螺纹常识,很基础
- 关于 chrome 上支付宝安全控件无法使用,以及检测不到数字证书的问题
- R语言—热力地图复合气泡饼图
- 计算机强制关机代码bat,自制bat文件搞定定时关机、重启、强制关机、注销等
- 软件测试人员的一般职业规划是如何的?
- 二十、HTTP 协议状态码-5XX
- JavaScript读书笔记(三)布尔值,null,undefined,全局对象,包装对象
热门文章
- maven整合@data注解_SpringBoot 整合 Dubbo实践(实用文章)
- 节能无线信标灯的几点补充测实验
- 蜗杆单轨滑轨的驱动的统一接口
- 全国大学生智能汽车竞赛证书打印方法
- 欠采样的基本概念和现象
- kalivm 虚拟机访问win文件夹_利用vmware搭建属于自己的win虚拟环境
- python分析b站_Python爬取并分析B站最热排行榜,我发现了这些秘密
- 用dblink能修改_【学习笔记】通过修改基表(link$)让非public dblink变为public
- linux系统下如何查看cpu能同时跑几个线程_探讨基于Linux的NUMA系统
- 卡住无法查看到所有进程_进程同步 进程互斥 软件和硬件实现方式 信号量机制 信号量机制实现进程同步,进程互斥,前驱关系...