您的位置:首页 > 其它

跟我一起学Windows界面封装(三) 之 前奏篇:窗口过程函数(上)

2013-04-25 21:30 423 查看

窗口过程函数

好,终于进入正题了。

在用MFC的时候,我们会发现MFC里面有消息映射,这么每个窗口类可以处理响应窗口消息,ATL也同样有自己的消息分发机制。由于窗口过程函数是全局函数(或静态函数),我们不可能吧一个程序的所有消息都在一个函数里面写,同时这个全局函数也没法和所有具体的窗口实例想绑定,即想调用具体类的成员函数都没办法实现,这样完成一个具有复杂功能的窗口程序也是不可能的了,我们上面的封装也一点意义都没了。为此,我们必须建立一个消息分发机制。

(1)方法1:映射表

在窗口过程函数参数中,我们看到有一个HWND参数,这是能让我们知道是哪个窗口发来的。由于HWND句柄是全局唯一不重复的,也和我们窗口实例有着一一对应的关系。由此,我们就想到可以维护一个全局的Map,如Map<HWND, Void*>,这样将HWND和窗口实例对象This指针建立一个映射表,进而就能够将消息分发到具体的窗口类了。

MFC就采用该方式,其维护了一个全局的哈希表来实现,代码就不再深究了。

在不计效率的情形下实现方法可如下:

_XWinModule中定义map<HWND,void*> 成员;
XWindowImpl的Create中首先将this指针保存到全局的临时指针中;
然后Create会调用CreateWindow,CreateWindow执行过程中会发送WM_CREATE、WM_NCCREATE等消息,我们窗口过程函数起始位置将HWND和之前临时区的this指针一起存到map中即可。有的朋友会说,你怎么知道this和hwnd是对应的,我想说我们的窗口过程是单线程的,而且保存完this后会马上执行createwindow,进而进入窗口过程函数中,这样改HWND肯定是和this是对应的。
后面就可以在窗口过程函数里面将消息分发到具体的实例中了。

部分代码如下:

XMoudle增加:

std::map<HWND, void*> m_MapObject;   // 保存映射关系的map
void* pTempThis;		    // 保存临时this的指针
void* AddXObject(void* pThis, HWND hWnd/* == nullptr*/)
{
if (hWnd == nullptr)
{
pTempThis = pThis;
return pTempThis;
}
else
{
ATLASSERT(pTempThis != nullptr);
m_MapObject.insert(std::make_pair(hWnd, pTempThis));
void* p = pTempThis;
pTempThis = nullptr;
return p;
}
}
void* GetXObject(HWND hWnd)
{
std::map<HWND, void*>::iterator it = m_MapObject.find(hWnd);
if (it != m_MapObject.end())
{
return it->second;
}
else
{
return nullptr;
}
}


注:实例中暂时不考虑多线程,否则就需要假如Thread ID等来保证线程安全。

然后再在XWindowImpl的Create第一行代码将this添加到module中去。

BOOL Create(int nCmdShow)
{
_XModule.AddXObject(this, nullptr);
… …
}
随后接收到消息中会进入WndProc,同时也会在第一条消息时将hwnd添加进去并和之前的this相对应,这样之后所有的消息都可以通过map查找到this并调用消息处理成员函数ProcessMessage

static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
void* p = _XModule.GetXObject(hWnd);
if (p == nullptr)
{
p = _XModule.AddXObject(nullptr, hWnd);
ATLASSERT(p != nullptr);
}

XWindowImpl<T, WinTrait>* pXWin = (XWindowImpl<T, WinTrait>*)p;
return pXWin->ProcessMessage(hWnd, message, wParam, lParam);
}


LRESULT ProcessMessage(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CLOSE:
DestroyWindow();
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return ::DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}




//注意:ProcessMessage()已经是类的成员函数了,不再是static函数了,因此进来的消息都是和自己相关的,不是自己的消息不会进入该函数。


                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: