跟我一起学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函数了,因此进来的消息都是和自己相关的,不是自己的消息不会进入该函数。
相关文章推荐
- 跟我一起学Windows界面封装(二) 之 前奏篇:显示第一个窗口
- 跟我一起学Windows界面封装(四) 之 窗口过程函数(下) -- 奇妙的Thunk技术
- 跟我一起学Windows界面封装(五) 之 封装第一个控件:按钮
- 跟我一起学Windows界面封装(六) 之 模态对话框原理
- 跟我一起学Windows界面封装(一) 之 基础篇:Win32 API
- 深入剖析WTL——如何封装Windows界面程序
- 深入剖析WTL——如何封装Windows界面程序
- Windows界面封装
- 深入剖析WTL——如何封装Windows界面程序
- 利用Windows绘制界面并且编写窗口过程函数
- Windows服务(Windows Service,system权限)程序显示界面与用户交互(xp,win7通用)
- 跟我一起学Windows Workflow Foundation(4)-----使用Listen,Delay,和其他envnt-based定制活动
- windows下无MySQL Command Line Client如何进行mysql命令行界面编辑
- 跟我一起学Windows Workflow Foundation(5)-----使用activity设计器创建一个整合的定制activity
- 使用wxpython开发windows界面
- 十分钟打造万能Windows封装包
- 设置界面的搭建和封装
- Windows系统网卡开启VLAN封装后与CISCO6509中继口不通
- C# Windows Api的一些方法 封装 以及 常用参数
- 如何将windows版的vim界面语言(默认为中文)设置成英文(转)