CWindowWnd类源码分析
CWindowWnd代码在UIBase.h和UIBase.cpp文件里。主要实现的是一个基本窗口的创建与消息处理。
相关代码:
头文件:
class UILIB_API CWindowWnd
{
public:
CWindowWnd(); HWND GetHWND() const;
operator HWND() const; bool RegisterWindowClass();
bool RegisterSuperclass(); HWND Create(HWND hwndParent, LPCTSTR pstrName, DWORD dwStyle, DWORD dwExStyle, const RECT rc, HMENU hMenu = NULL);
HWND Create(HWND hwndParent, LPCTSTR pstrName, DWORD dwStyle, DWORD dwExStyle, int x = CW_USEDEFAULT, int y = CW_USEDEFAULT, int cx = CW_USEDEFAULT, int cy = CW_USEDEFAULT, HMENU hMenu = NULL);
HWND CreateDuiWindow(HWND hwndParent, LPCTSTR pstrWindowName,DWORD dwStyle =, DWORD dwExStyle =);
HWND Subclass(HWND hWnd);
void Unsubclass();
void ShowWindow(bool bShow = true, bool bTakeFocus = true);
UINT ShowModal();
void Close(UINT nRet = IDOK);
void CenterWindow(); // 居中,支持扩展屏幕
void SetIcon(UINT nRes); LRESULT SendMessage(UINT uMsg, WPARAM wParam = , LPARAM lParam = 0L);
LRESULT PostMessage(UINT uMsg, WPARAM wParam = , LPARAM lParam = 0L);
void ResizeClient(int cx = -, int cy = -); protected:
virtual LPCTSTR GetWindowClassName() const = ;
virtual LPCTSTR GetSuperClassName() const;
virtual UINT GetClassStyle() const; virtual LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam);
virtual void OnFinalMessage(HWND hWnd); static LRESULT CALLBACK __WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
static LRESULT CALLBACK __ControlProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); protected:
HWND m_hWnd;
WNDPROC m_OldWndProc;
bool m_bSubclassed;
};
源文件:
//////////////////////////////////////////////////////////////////////////
///
CWindowWnd::CWindowWnd() : m_hWnd(NULL), m_OldWndProc(::DefWindowProc), m_bSubclassed(false)
{
} HWND CWindowWnd::GetHWND() const
{
return m_hWnd;
} UINT CWindowWnd::GetClassStyle() const
{
return ;
} LPCTSTR CWindowWnd::GetSuperClassName() const
{
return NULL;
} CWindowWnd::operator HWND() const
{
return m_hWnd;
} HWND CWindowWnd::CreateDuiWindow( HWND hwndParent, LPCTSTR pstrWindowName,DWORD dwStyle /*=0*/, DWORD dwExStyle /*=0*/ )
{
return Create(hwndParent,pstrWindowName,dwStyle,dwExStyle,,,,,NULL);
} HWND CWindowWnd::Create(HWND hwndParent, LPCTSTR pstrName, DWORD dwStyle, DWORD dwExStyle, const RECT rc, HMENU hMenu)
{
return Create(hwndParent, pstrName, dwStyle, dwExStyle, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, hMenu);
} //调用创建win32创建窗口的API
//如果是控件则GetSuperClassName返回非NULL 调用RegisterSuperclass
//否则调用RegisterWindowClass
//然后使用CreateWindowEx创建窗口
HWND CWindowWnd::Create(HWND hwndParent, LPCTSTR pstrName, DWORD dwStyle, DWORD dwExStyle, int x, int y, int cx, int cy, HMENU hMenu)
{
if( GetSuperClassName() != NULL && !RegisterSuperclass() ) return NULL;
if( GetSuperClassName() == NULL && !RegisterWindowClass() ) return NULL;
m_hWnd = ::CreateWindowEx(dwExStyle, GetWindowClassName(), pstrName, dwStyle, x, y, cx, cy, hwndParent, hMenu, CPaintManagerUI::GetInstance(), this);
ASSERT(m_hWnd!=NULL);
return m_hWnd;
} //子类化一个控件 m_OldWndProc 保存旧消息处理函数
HWND CWindowWnd::Subclass(HWND hWnd)
{
ASSERT(::IsWindow(hWnd));
ASSERT(m_hWnd==NULL);
m_OldWndProc = SubclassWindow(hWnd, __WndProc);
if( m_OldWndProc == NULL ) return NULL;
m_bSubclassed = true;
m_hWnd = hWnd;
::SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast<LPARAM>(this));
return m_hWnd;
} //恢复之类化的控件
void CWindowWnd::Unsubclass()
{
ASSERT(::IsWindow(m_hWnd));
if( !::IsWindow(m_hWnd) ) return;
if( !m_bSubclassed ) return;
SubclassWindow(m_hWnd, m_OldWndProc);
m_OldWndProc = ::DefWindowProc;
m_bSubclassed = false;
} void CWindowWnd::ShowWindow(bool bShow /*= true*/, bool bTakeFocus /*= false*/)
{
ASSERT(::IsWindow(m_hWnd));
if( !::IsWindow(m_hWnd) ) return;
::ShowWindow(m_hWnd, bShow ? (bTakeFocus ? SW_SHOWNORMAL : SW_SHOWNOACTIVATE) : SW_HIDE);
} //实现一个modal窗口
UINT CWindowWnd::ShowModal()
{
ASSERT(::IsWindow(m_hWnd));
UINT nRet = ;
HWND hWndParent = GetWindowOwner(m_hWnd);
::ShowWindow(m_hWnd, SW_SHOWNORMAL);
::EnableWindow(hWndParent, FALSE);
MSG msg = { };
while( ::IsWindow(m_hWnd) && ::GetMessage(&msg, NULL, , ) ) {
if( msg.message == WM_CLOSE && msg.hwnd == m_hWnd ) {
nRet = msg.wParam;
::EnableWindow(hWndParent, TRUE);
::SetFocus(hWndParent);
}
if( !CPaintManagerUI::TranslateMessage(&msg) ) {
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
if( msg.message == WM_QUIT ) break;
}
::EnableWindow(hWndParent, TRUE);
::SetFocus(hWndParent);
if( msg.message == WM_QUIT ) ::PostQuitMessage(msg.wParam);
return nRet;
} void CWindowWnd::Close(UINT nRet)
{
ASSERT(::IsWindow(m_hWnd));
if( !::IsWindow(m_hWnd) ) return;
PostMessage(WM_CLOSE, (WPARAM)nRet, 0L);
} void CWindowWnd::CenterWindow()
{
ASSERT(::IsWindow(m_hWnd));
ASSERT((GetWindowStyle(m_hWnd)&WS_CHILD)==);
RECT rcDlg = { };
::GetWindowRect(m_hWnd, &rcDlg);
RECT rcArea = { };
RECT rcCenter = { };
HWND hWnd=*this;
HWND hWndParent = ::GetParent(m_hWnd);
HWND hWndCenter = ::GetWindowOwner(m_hWnd);
if (hWndCenter!=NULL)
hWnd=hWndCenter; // 处理多显示器模式下屏幕居中
MONITORINFO oMonitor = {};
oMonitor.cbSize = sizeof(oMonitor);
::GetMonitorInfo(::MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST), &oMonitor);
rcArea = oMonitor.rcWork; if( hWndCenter == NULL )
rcCenter = rcArea;
else
::GetWindowRect(hWndCenter, &rcCenter); int DlgWidth = rcDlg.right - rcDlg.left;
int DlgHeight = rcDlg.bottom - rcDlg.top; // Find dialog's upper left based on rcCenter
int xLeft = (rcCenter.left + rcCenter.right) / - DlgWidth / ;
int yTop = (rcCenter.top + rcCenter.bottom) / - DlgHeight / ; // The dialog is outside the screen, move it inside
if( xLeft < rcArea.left ) xLeft = rcArea.left;
else if( xLeft + DlgWidth > rcArea.right ) xLeft = rcArea.right - DlgWidth;
if( yTop < rcArea.top ) yTop = rcArea.top;
else if( yTop + DlgHeight > rcArea.bottom ) yTop = rcArea.bottom - DlgHeight;
::SetWindowPos(m_hWnd, NULL, xLeft, yTop, -, -, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
} //从资源设置图标
void CWindowWnd::SetIcon(UINT nRes)
{
HICON hIcon = (HICON)::LoadImage(CPaintManagerUI::GetInstance(), MAKEINTRESOURCE(nRes), IMAGE_ICON,
(::GetSystemMetrics(SM_CXICON) + ) & ~, (::GetSystemMetrics(SM_CYICON) + ) & ~, // 防止高DPI下图标模糊
LR_DEFAULTCOLOR);
ASSERT(hIcon);
::SendMessage(m_hWnd, WM_SETICON, (WPARAM) ICON_SMALL, (LPARAM) hIcon); hIcon = (HICON)::LoadImage(CPaintManagerUI::GetInstance(), MAKEINTRESOURCE(nRes), IMAGE_ICON,
(::GetSystemMetrics(SM_CXICON) + ) & ~, (::GetSystemMetrics(SM_CYICON) + ) & ~, // 防止高DPI下图标模糊
LR_DEFAULTCOLOR);
ASSERT(hIcon);
::SendMessage(m_hWnd, WM_SETICON, (WPARAM) ICON_BIG, (LPARAM) hIcon);
} bool CWindowWnd::RegisterWindowClass()
{
WNDCLASS wc = { };
wc.style = GetClassStyle();
wc.cbClsExtra = ;
wc.cbWndExtra = ;
wc.hIcon = NULL;
wc.lpfnWndProc = CWindowWnd::__WndProc;
wc.hInstance = CPaintManagerUI::GetInstance();
wc.hCursor = ::LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = NULL;
wc.lpszMenuName = NULL;
wc.lpszClassName = GetWindowClassName();
ATOM ret = ::RegisterClass(&wc);
ASSERT(ret!=NULL || ::GetLastError()==ERROR_CLASS_ALREADY_EXISTS);
return ret != NULL || ::GetLastError() == ERROR_CLASS_ALREADY_EXISTS;
} //这里应该是创建一个控件类,子类化过的
bool CWindowWnd::RegisterSuperclass()
{
// Get the class information from an existing
// window so we can subclass it later on...
WNDCLASSEX wc = { };
wc.cbSize = sizeof(WNDCLASSEX);
if( !::GetClassInfoEx(NULL, GetSuperClassName(), &wc) ) {
if( !::GetClassInfoEx(CPaintManagerUI::GetInstance(), GetSuperClassName(), &wc) ) {
ASSERT(!"Unable to locate window class");
return NULL;
}
}
m_OldWndProc = wc.lpfnWndProc;
wc.lpfnWndProc = CWindowWnd::__ControlProc;
wc.hInstance = CPaintManagerUI::GetInstance();
wc.lpszClassName = GetWindowClassName();
ATOM ret = ::RegisterClassEx(&wc);
ASSERT(ret!=NULL || ::GetLastError()==ERROR_CLASS_ALREADY_EXISTS);
return ret != NULL || ::GetLastError() == ERROR_CLASS_ALREADY_EXISTS;
} //默认的消息处理函数 注册窗口时使用过
LRESULT CALLBACK CWindowWnd::__WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
CWindowWnd* pThis = NULL;
if( uMsg == WM_NCCREATE ) {
//首次创建窗口时调用
LPCREATESTRUCT lpcs = reinterpret_cast<LPCREATESTRUCT>(lParam);
pThis = static_cast<CWindowWnd*>(lpcs->lpCreateParams);
pThis->m_hWnd = hWnd;
::SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast<LPARAM>(pThis));
}
else {
pThis = reinterpret_cast<CWindowWnd*>(::GetWindowLongPtr(hWnd, GWLP_USERDATA));
//销毁窗口时调用
if( uMsg == WM_NCDESTROY && pThis != NULL ) {
//把消息传递到上一层
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;
//调用OnFinalMessage OnFinalMessage一般做最后的处理
pThis->OnFinalMessage(hWnd);
return lRes;
}
}
if( pThis != NULL ) {
//调用HandleMessage来处理消息
return pThis->HandleMessage(uMsg, wParam, lParam);
}
else {
return ::DefWindowProc(hWnd, uMsg, wParam, lParam);
}
} //控件的消息处理函数
LRESULT CALLBACK CWindowWnd::__ControlProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
CWindowWnd* pThis = NULL;
if( uMsg == WM_NCCREATE ) {
LPCREATESTRUCT lpcs = reinterpret_cast<LPCREATESTRUCT>(lParam);
pThis = static_cast<CWindowWnd*>(lpcs->lpCreateParams);
::SetProp(hWnd, _T("WndX"), (HANDLE) pThis);
pThis->m_hWnd = hWnd;
}
else {
pThis = reinterpret_cast<CWindowWnd*>(::GetProp(hWnd, _T("WndX")));
if( uMsg == WM_NCDESTROY && pThis != NULL ) {
LRESULT lRes = ::CallWindowProc(pThis->m_OldWndProc, hWnd, uMsg, wParam, lParam);
if( pThis->m_bSubclassed ) pThis->Unsubclass();
::SetProp(hWnd, _T("WndX"), NULL);
pThis->m_hWnd = NULL;
pThis->OnFinalMessage(hWnd);
return lRes;
}
}
if( pThis != NULL ) {
return pThis->HandleMessage(uMsg, wParam, lParam);
}
else {
return ::DefWindowProc(hWnd, uMsg, wParam, lParam);
}
} LRESULT CWindowWnd::SendMessage(UINT uMsg, WPARAM wParam /*= 0*/, LPARAM lParam /*= 0*/)
{
ASSERT(::IsWindow(m_hWnd));
return ::SendMessage(m_hWnd, uMsg, wParam, lParam);
} LRESULT CWindowWnd::PostMessage(UINT uMsg, WPARAM wParam /*= 0*/, LPARAM lParam /*= 0*/)
{
ASSERT(::IsWindow(m_hWnd));
return ::PostMessage(m_hWnd, uMsg, wParam, lParam);
} void CWindowWnd::ResizeClient(int cx /*= -1*/, int cy /*= -1*/)
{
ASSERT(::IsWindow(m_hWnd));
RECT rc = { };
if( !::GetClientRect(m_hWnd, &rc) ) return;
if( cx != - ) rc.right = cx;
if( cy != - ) rc.bottom = cy;
if( !::AdjustWindowRectEx(&rc, GetWindowStyle(m_hWnd), (!(GetWindowStyle(m_hWnd) & WS_CHILD) && (::GetMenu(m_hWnd) != NULL)), GetWindowExStyle(m_hWnd)) ) return;
::SetWindowPos(m_hWnd, NULL, , , rc.right - rc.left, rc.bottom - rc.top, SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
} //虚函数 用于在子类里重写此函数接管消息
LRESULT CWindowWnd::HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
return ::CallWindowProc(m_OldWndProc, m_hWnd, uMsg, wParam, lParam);
} void CWindowWnd::OnFinalMessage(HWND /*hWnd*/)
{
} //////////////////////////////////////////////////////////////////////////
流程:
调用Create创建一个窗口,使用RegisterSuperclass或RegisterWindowClass注册类,调用CreateWindowEx创建窗口返回句柄。
RegisterSuperclass使用CWindowWnd::__ControlProc作为窗口消息处理函数,
RegisterWindowClass使用CWindowWnd::__WndProc作为消息处理函数。
两个消息处理函数除了WM_NCDESTROY以外其他消息都通过HandleMessage来处理,所以继承类中只要重载HandleMessage就可以处理大部分消息了。
CWindowWnd类源码分析的更多相关文章
- List 接口以及实现类和相关类源码分析
List 接口以及实现类和相关类源码分析 List接口分析 接口描述 用户可以对列表进行随机的读取(get),插入(add),删除(remove),修改(set),也可批量增加(addAll),删除( ...
- Cocos2d-X3.0 刨根问底(六)----- 调度器Scheduler类源码分析
上一章,我们分析Node类的源码,在Node类里面耦合了一个 Scheduler 类的对象,这章我们就来剖析Cocos2d-x的调度器 Scheduler 类的源码,从源码中去了解它的实现与应用方法. ...
- Java Properties类源码分析
一.Properties类介绍 java.util.Properties继承自java.util.Hashtable,从jdk1.1版本开始,Properties的实现基本上就没有什么大的变动.从ht ...
- java中List接口的实现类 ArrayList,LinkedList,Vector 的区别 list实现类源码分析
java面试中经常被问到list常用的类以及内部实现机制,平时开发也经常用到list集合类,因此做一个源码级别的分析和比较之间的差异. 首先看一下List接口的的继承关系: list接口继承Colle ...
- Java并发编程笔记之Unsafe类和LockSupport类源码分析
一.Unsafe类的源码分析 JDK的rt.jar包中的Unsafe类提供了硬件级别的原子操作,Unsafe里面的方法都是native方法,通过使用JNI的方式来访问本地C++实现库. rt.jar ...
- String 类源码分析
String 源码分析 String 类代表字符序列,Java 中所有的字符串字面量都作为此类的实例. String 对象是不可变的,它们的值在创建之后就不能改变,因此 String 是线程安全的. ...
- Cocos2d-X3.0 刨根问底(三)----- Director类源码分析
上一章我们完整的跟了一遍HelloWorld的源码,了解了Cocos2d-x的启动流程.其中Director这个类贯穿了整个Application程序,这章随小鱼一起把这个类分析透彻. 小鱼的阅读源码 ...
- Java线程池ThreadPoolExecutor类源码分析
前面我们在java线程池ThreadPoolExecutor类使用详解中对ThreadPoolExector线程池类的使用进行了详细阐述,这篇文章我们对其具体的源码进行一下分析和总结: 首先我们看下T ...
- Spring之WebContext不使用web.xml启动 初始化重要的类源码分析(Servlet3.0以上的)
入口: org.springframework.web.SpringServletContainerInitializer implements ServletContainerInitializer ...
随机推荐
- Java中Thread类的join方法到底是如何实现等待
现在的场景是A线程执行:public void run(){ bThread.join(0);//把b线程加入到当前线程(a线程),等待b结束,当前a线程才会结束.}B线程执行public void ...
- 了解Mysql与MariaDb的关系
MariaDB是MySQL源代码的一个分支,随着Oracle买下Sun,MySQL也落入了关系型数据库王者之手.在意识到Oracle会对MySQL许可做什么后便分离了出来(MySQL先后被Sun.Or ...
- Ajax实现异步操作实例_针对JSON格式的请求数据
最近写了一篇ajax异步操作XML格式的,今天就写关于json格式的. 一.简单了解Json 1. JSON有两种表示结构,对象和数组. 1.1 对象: { key1:value1, key2:val ...
- andorid 网络通信最简单demo
要和后台进行通信 一开始发现接不到数据 后来发生了线程错误 在网上查到:在一些高版本中,与网络通信的操作因为要花费比较大的时间,所以应该放在单独的线程中去做. 但为什么一些网上demo没有放在单独的线 ...
- iOS | Swift图片剪切圆角
我们在IOS开发中,时常需要将一些原本是方形的图片剪切成圆形或者边框是曲线的样子,表现得活泼生动一些. 注意:因为最近在尝试用Swiftl开发,所以这里的语言使用的就是Swift,OC的语法也是相近的 ...
- ionic 安装步骤
安装ionic和cordova 1,需要首先安装好nodejs,然后通过npm来安装 npm install -g cordova ionic 注意:可能遇到的错误:Error: Cannot fi ...
- Django从请求到返回流程
图1:流程图 1. 用户通过浏览器请求一个页面2.请求到达Request Middlewares,中间件对request做一些预处理或者直接response请求3.URLConf通过urls.py文件 ...
- ATX 浅谈自动化测试工具 python-uiautomator2
1.简介 python-uiautomator2是一个自动化测试开源工具,仅支持Android平台的原生应用测试. 2.支持平台及语言 python-uiautomator2封装了谷歌自带的uiaut ...
- Python入门学习笔记4:他人的博客及他人的学习思路
看其他人的学习笔记,可以保证自己不走弯路.并且一举两得,即学知识又学方法! 廖雪峰:https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958 ...
- 为什么我要放弃javaScript数据结构与算法(第三章)—— 栈
有两种结构类似于数组,但在添加和删除元素时更加可控,它们就是栈和队列. 第三章 栈 栈数据结构 栈是一种遵循后进先出(LIFO)原则的有序集合.新添加的或待删除的元素都保存在栈的同一端,称为栈顶,另一 ...