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 ...
随机推荐
- CENTOS 6 通过YUM升级GCC到4.7/4.8
第一阶段:升级到4.7 [root@01314.CN ~]# cd /etc/yum.repos.d [root@01314.CN yum.repos.d]# wget http://people.c ...
- 【洛谷P2470】[SCOI2007]压缩
压缩 #include<iostream> #include<cstring> #include<cstdio> using namespace std; #def ...
- Android学习笔记_67_Android MyCrashHandler 中异常处理 UncaughtExceptionHandler
1.程序中故意抛出异常: public class ExceptionActivity extends Activity { String str; @Override public void onC ...
- HTML中id和class选择器
<1>.id和class的区别? id相当于人的身份证不可以重复 class相当于人的名称可以重复 一个HTML标签只能绑定一个id名称 一个HTML标签可以绑定多个class名称 < ...
- iOS之蓝牙开发—CoreBluetooth详解
CoreBluetooth的API是基于BLE4.0的标准的.这个框架涵盖了BLE标准的所有细节.仅仅只有新的iOS设备和Mac是和BLE标准兼容.在CoreBluetooth框架中,有两个主要的角色 ...
- rest_framework -- 认证组件
#####认证组件##### 一.认证是什么就不说了,某些网页必须是用户登陆之后,才能访问的,所以这时候就需要用上认证组件. 你不用rest_framework的认证组件也行,这种认证的话,完全可以自 ...
- 肝题与oj
oier很多,oj也很多,这些oj分别有怎样的特点,我们又该怎样选择呢?请各位客官听在下分解 (我主要说一些比较大众的oj) (注意:难度与界面友好度为个人意见,不喜勿喷) 1.入门级 1.NOIop ...
- shardedJedisPool工具类
这里使用的是ShardedJedisPool,而不是RedisTemplate 1.配置文件 <?xml version="1.0" encoding="UTF-8 ...
- 在Liunx Mint下无法切换到root用户
提示 su: Authentication failure 以ubuntu的mint root用户默认是也是禁止的 需要手动打开才行 a)root启用 执行下面的操作:1.先解除root锁定,为roo ...
- PHP导出数据到表格的实例
我发现最近的项目需要导出Excel表的页面非常的多,想来这个也是我们常用的功能了,现在我可以很熟练的导出了,但是记得当时自己第一次导出时还是绕了一些弯路的,那么现在我就来记录下我这次用exshop框架 ...