概论:
类的非static函数本身含有一个this指针,所以这种函数不能作为一个窗口过程(callback function )。当使用static函数来做一个窗口过程函数时,static函数可以通过编译,但是它本身无法访问类的成员函数和数据,如果我们能够得到类的指针并交给static函数处理则可以实现我们的要求。
技巧:
为了确保非static窗口过程能够处理所有的消息,所以我们使用了CBT Hook(),这样我们就可以在窗口创建之前把类的指针交给static的窗口过程,他就可以调用类的成员函数。
在这个过程当中,我们还使用了Thread Local Storage (TLS)。
步骤:
1:分配一个TLS空间来保存this指针。
DWORD TlsIndex=::TlsAlloc();
2: 声明一个结构体TLSData,将this指针和HHOOK句柄保存下来,将他的指针放在在TLS中。
TLSData* pTLSCreateData = new TLSData;
pTLSCreateData->hHook=hHook; //hHook=::SetWindowsHookEx(WH_CBT,
//CWin::StaticCBTProc, 0, ::GetCurrentThreadId());
pTLSCreateData->pThis = this;
::TlsSetValue(TlsIndex //就是上面TlsIndex=::TlsAlloc();
, pTLSCreateData);
3:在窗口创建之前,HCBT_CREATEWND 消息会发送给staticCBTProc也就是hHook的回调函数。
TLSData* pTLSCreateData = (TLSData*)TlsGetValue(TlsIndex);
~~~~~ * w = (~~~~~~*) pTLSCreateData->pThis;//~~~~~:表示对应的那个类。
::SetWindowLong((HWND) wParam, GWL_USERDATA, (LONG)w);
//说明;这里的pTLSCreateData->hHook,
//是给函数CallNextHookEx(pTLSCreateData->hHook, msg, wParam, lParam);服务的。
4:在注册窗口类时,已经把一个static函数注册成为他的窗口过程,所以在这个函数中,我们把指针交给他处理。
~~~~~ *w = (~~~~~~*) (LONG)::GetWindowLong(hWnd, GWL_USERDATA);
return w->WndProc(hWnd, uMsg, wParam, lParam);
5 :即时的
::UnhookWindowsHookEx(hHook);
delete pTLSCreateData;
::TlsSetValue(TlsIndex, NULL);
总结:方法是死的,重要的是灵活运用。