为什么要讨论这个问题?
因为原来的window 所有的设计都是基于c过程的, 没有对象的概念.
后来大家都开始用c++开始编程, 当然也包括win32客户端开发.
用c++类封装一个普通窗口, 是c++开发客户端的最开始最基本的问题.
我们平时不太接触这个问题, 是因为我们基本都是基于某个开发框架写自己的客户端程序的, 比如MFC, WTL, QT等, 甚至包括DuiLib这个小型的皮肤框架.
这个框架都为我们封装好了, 所以我们其实最开始不需要考虑这个问题(到底c++类是怎么做到封装win32窗口的).
但是, 随着开发的深入, 你会发现你需要自己封装一个, 比如, 你要自己做一个简版的开发框架.
下面就简单介绍一下这个问题.
窗口类大概声明如下.
class CWndFrame
{
public:
HWND m_hwnd;
LRESULT HandleMessage().
void Create();
}
其实封装的关键, 就是用类自己的HandleMessage, 替换掉窗口过程.
或者说, 在窗口过程中, 能任意地调用CWndFrame的函数, 这样就需要把CWndFrame的this指针传递到窗口过程中去.
windows在创建窗口的时候, 允许传入一个自定义字段, 而这个字段就是我们可以利用的.
CWndFrame::Create()
{
m_hWnd = ::CreateWindowEx(dwExStyle, szWindowClass, szTitle, dwStyle, x, y, cx, cy, hwndParent, hMenu, hInst, this);
//这里的最后一个参数就是我们传入的this指针.
}
这样, 在窗口过程中,
处理WM_NCCREATE消息时.
pThis = static_cast<CBrowserFrame*>(lpcs->lpCreateParams);
//lparam是CREATESTRUCT的指针, 其中就有我们需要的this指针.
至于为什么在处理这个消息的时候做这件事, 因为这是消息循环的开始.
然后
::SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast<LPARAM>(pThis));
把this指针存放在窗口的一个特殊的extra位置GWLP_USERDATA, 这个位置部分用途就是 用来存自定义内容.
然后, 每次窗口过程启动的时候,
调用GetWindowLongPtr取出this指针, 然后在窗口过程中调用this->HandleMessage.
如上, 这样就用窗口类自己的成员函数替换掉了窗口过程.
参考代码如下:
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { CBrowserFrame* pThis = NULL; if( message == WM_NCCREATE ) { LPCREATESTRUCT lpcs = reinterpret_cast<LPCREATESTRUCT>(lParam); pThis = static_cast<CBrowserFrame*>(lpcs->lpCreateParams); pThis->m_hWnd = hWnd; ::SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast<LPARAM>(pThis)); } else { pThis = reinterpret_cast<CBrowserFrame*>(::GetWindowLongPtr(hWnd, GWLP_USERDATA)); if( message == WM_NCDESTROY && pThis != NULL ) { //By Jackie 2013-10-24 先别动这个代码, 我给注掉了, 貌似没什么影响. //除非旧的过程中有特殊调用, 或者GWLP_USERDATA有其他特殊用途 //LRESULT lRes = ::CallWindowProc(pThis->m_OldWndProc, hWnd, uMsg, wParam, lParam); //::SetWindowLongPtr(pThis->m_hWnd, GWLP_USERDATA, 0L); //if( pThis->m_bSubclassed ) pThis->Unsubclass(); //pThis->m_hWnd = NULL; //pThis->OnFinalMessage(hWnd); return 0; } } if( pThis != NULL ) { return pThis->HandleMessage(message, wParam, lParam); } else { return ::DefWindowProc(hWnd, message, wParam, lParam); }