I want to call SetWindowsHookEx to set the WH_CBT hook, but I understand that MFC also installed this hook, that is, in a thread installed two times WH_CBT, this can do?
Ken Dang
The answer is yes. Just follow the correct steps and you can install several hooks of the same type. Windows hooks are designed for a series of operations like subclasses. To install the hook, call the SetWindowsHookEx function, which is the hook type and a pointer to the hook process. SetWindowsHookEx returns a handle pointing to the old hook:HHOOK hOldHook; // 全局
...
hOldHook = SetWindowsHookEx(WH_CBT, MyCbtProc, ...);
Now whenever there is a hook event, Windows calls your hook process. When your process is done with the event, you should call the next hook with CallNextHookEx:
LRESULT CALLBACK
MyCbtProc(int code, ...)
{
if (code==/* whatever */) {
// do something
}
return CallNextHookEx(hOldHook, code, ...);
}
Of course, no one is forcing you to call CallNextHookEx, but if you don't call, your program may collapse. MFC uses CBT hooks to monitor the creation of Windows. Windows will call this CBT hook with Hcbt_createwnd as soon as you create a window. MFC handles Hcbt_createwnd through a subclass window, and it is attached to its CWnd object. The details are more complex, and here's a simple version of the code:
// 来自 wincore.cpp 的简化代码
LRESULT _AfxCbtFilterHook(int code, WPARAM wp, ...)
{
if (code==HCBT_CREATEWND) {
CWnd* pWndInit = pThreadState- >m_pWndInit;
HWND hWnd = (HWND)wp;
pWndInit->Attach(hWnd);
SetWindowLongPtr(hWnd, GWLP_WNDPROC, &AfxWndProcafxWndProc);
}
return CallNextHookEx(...);
}
Here is the code after the refine, MFC to subordinate the Window object to its HWND and through the installation AfxWndProc to subclass it. It is in this way that MFC links C + + window objects with their hwnds. The role of the AFXWNDPROC process is to route the WM_XXX message to your message map handler (through a very tortuous path).
When Windows invokes a CBT hook, it passes the HWND with WPARAM. But how does MFC know which CWnd derived objects to associate with? Through a global variable. In order to create a window, you must call CWnd::Create or Cwnd::createex. The former calls the latter, so it has to go through the Cwnd::createex call anyway. Before creating the window, Cwnd::createex installs the CBT hook and sets the global variable. The code is like this:
// 来自 wincore.cpp 的简 化代码
BOOL CWnd::CreateEx(...)
{
AfxHookWindowCreate(this);
::CreateWindowEx(...);
AfxUnhookWindowCreate();
return TRUE;
}
Afxhookwindowcreate installs the CBT hook _afxcbtfilterhook. It also saves the window object pointer in thread state, Pthreadstate->m_pwndinit.
void AFXAPI AfxHookWindowCreate(CWnd* pWnd)
{
_AFX_THREAD_STATE* pThreadState = _afxThreadState.GetData();
pThreadState->m_hHookOldCbtFilter = ::SetWindowsHookEx(
WH_CBT, _AfxCbtFilterHook, NULL, ::GetCurrentThreadId());
pThreadState->m_pWndInit = pWnd;
}