应用小窗口化,窗口化应用程序
所谓窗口子类化:改变一个已经存在的窗口实例的性质:消息处理与其他实例属性。
通常在软件开发工具包(软件开发工具包)中所谓的窗口子类化就是改变一个窗口函数(如GetWindowLong()和SetWindowLong())通过这两个函数来设置窗口的属性等;
而今天我们主要内容是介绍MS-VisualC++的类库(微软基础班的缩写)中的子类化,它跟软件开发工具包(软件开发工具包)中的子类化不太一样:
所有MS-VisualC++的类库(微软基础班的缩写)窗口有相同的窗口函数,由该窗口函数根据窗口句柄查找窗口实例,在把消息映射到该窗口类(类别)得消息处理函数上。为了利用MS-VisualC++的类库(微软基础班的缩写)的消息映射机制,不宜改变窗口函数(名),MFC也把子类化封装在函数子类窗口()中。
#include Subclass.h
classCSubclassWnd:公共对象{
公共:
DECLARE _ DYNAMIC(CSubclassWnd);
CSubclassWnd();
~ CSubclassWnd();
//子类化一个窗口钩子(空)到脱钩(在WM_NCDESTROY上自动)
虚拟BOOLHookWindow(HWNDhwnd);
虚拟BOOLHookWindow(CWnd * pWnd){返回挂钩窗口(pWnd-GetSafeHwnd());}
虚拟boolishoked(){ return m _ hWnd!=NULL}
朋友结果回调HookWndProc(HWND,UINT,WPARAM,LPARAM);
友类CSubclassWndMap
#ifdef _DEBUG
虚拟void AssertValid()常量;
虚拟void Dump(CDumpContext dc)常量;
#endif
受保护:
HWNDm _ hWnd//窗口被钩住
WNDPROCm _ pOldWndProc//.和原始窗口进程
CSubclassWnd * m _ pNext//此窗口挂钩链中的下一个
//重写此方法以在特定的处理程序中处理消息
虚拟LRESULT WindowProc(UINT msg,WPARAM wp,LPARAM LP);
虚拟LRESULT Default();//在处理程序小脑顶核电刺激的末尾调用这个函数
};
#include Subclass.cpp
CSubclassWnd:CSubclassWnd()
{
m _ pNext=NULL
m _ pOldWndProc=NULL
m _ hWnd=NULL
}
CSubclassWnd:~CSubclassWnd()
{
if (m_hWnd)
钩子窗口((HWND)NULL);//解除窗口挂钩
}
//////////////////
//挂钩一个窗口。
//这会安装一个新的窗口过程,将消息定向到CSubclassWnd .
//pWnd=NULL以移除。
//
BOOL CSubclassWnd:HookWindow
{
ASSERT _ VALID(this);
if (hwnd) {
//挂钩窗口
ASSERT(m _ hWnd==NULL);
ASSERT(:is窗口(hwnd));
地图。添加(hwnd,这个);//添加到挂钩地图
} else if (m_hWnd) {
//解开窗口
地图。去掉(这个);//从地图中移除
m _ pOldWndProc=NULL
}
m _ hWnd=hwnd
返回真实的
}
//////////////////
//窗口类似过程的虚函数
//覆盖来做事情违约将消息传递给下一个钩子;
//最后一个钩子将消息传递给原始窗口。
//如果您想要真正的
//窗口来获取消息。这就像CWnd:WindowProc,除了
//CSubclassWnd不是窗口。
//
LRESULT CSubclassWnd:窗口进程(UINT msg,WPARAM wp,LPARAM lp)
{
//ASSERT _ VALID(this);//因速度原因而移除
ASSERT(m _ pOldWndProc);
返回m_pNext?m_pNext- WindowProc(msg,wp,lp):
* CallWindowProc(m _ pOldWndProc,m_hWnd,msg,wp,LP);
}
//////////////////
//像调用基类WindowProc但是不带参数,所以个性
//消息处理程序可以做默认的事情。像CWnd:默认值
//
LRESULT CSubclassWnd:Default()
{
//MFC在线程状态中存储当前消息
MSG curMsg=AfxGetThreadState()-m _ lastSentMsg;
//注意:必须显式调用CSubclassWnd:WindowProc以避免不限制
//虚函数上的递归
返回CSubclassWnd:窗口过程(curmsg。消息,curMsg.wParam,curMsg。lparam);
}
#ifdef _DEBUG
void CSubclassWnd:assert valid()const
{
CObject:assert valid();
ASSERT(m _ hWnd==NULL :is window(m _ hWnd));
if (m_hWnd) {
for (CSubclassWnd* p=theHookMap .lookup(m _ hWnd);p;p=p- m_pNext) {
如果(p==这个)
打破;
}
断言(p);//应该已经找到了!
}
}
void CSubclassWnd:Dump(CDumpContext DC)常量
{
CObject:Dump(DC);
}
#endif
//////////////////
//消息挂钩的子类窗口过程。取代AfxWndProc(或其他
//否则之前在。)
//
LRESULT回调
HookWndProc(HWND hwnd,UINT msg,WPARAM wp,LPARAM lp)
{
#ifdef _USRDLL
//如果这是一个DLL,需要设置MS-VisualC++的类库(Microsoft Foundation Class的缩写)状态
AFX _ MANAGE _ STATE(AfxGetStaticModuleState());
#endif
//设置MS-VisualC++的类库(Microsoft Foundation Class的缩写)消息状态,以防有人需要它
//这就像AfxCallWindowProc一样,但是我们不能使用它,因为
//CSubclassWnd不是CWnd .
//
MSG curMsg=AfxGetThreadState()-m _ lastSentMsg;
MSGoldMsg=curMsg//保存以便嵌套
curMsg.hwnd=hwnd
curMsg.message=msg
curMsg.wParam=wp
curMsg.lParam=lp
//获取此窗口的挂钩对象。从挂钩地图获取
CSubclassWnd * pSubclassWnd=theHookMap .查找(hwnd);
ASSERT(pSubclassWnd);
lr结果lr
if (msg==WM_NCDESTROY) {
//窗口正在被破坏:解开所有挂钩(对于此窗口)
//并将消息传递给原始窗口进程
//
WNDPROC WNDPROC=pSubclassWnd-m _ pOldWndProc;
地图移除所有(hwnd);
lr=:CallWindowProc(wndproc,hwnd,msg,wp,LP);
}否则{
//传递给消息挂钩
lr=pSubclassWnd- WindowProc(msg,wp,LP);
}
curMsg=oldMsg//弹出状态
返回lr;
}
这边只是介绍子类窗口()内部实现方式。
CSubclassWnd类的作用是不用派生新类便能在MS-VisualC++的类库(微软基础班的缩写)中子类化窗口。
现在我们这边只提CSubclass Wnd类的一个作用,其实CSubclass Wnd也经常被说成是万能类,可以用在很多的界面和控件上。
具体实例:
以美图秀秀的弹出对话框自定义皮肤为例:
创建一个自定义皮肤类:
类CDlgSkin:公共CSubclassWnd
{
公共:
自定义变量
CDlgSkin();
CDlgSkin(LPCTSTR skinfile)
{
CDlgSkin();
LoadSkin(皮肤文件);
}
virtual ~ CDlgSkin();
BOOL InitSkinWin(CString strPath,CWnd * wnd);
虚拟LRESULT WindowProc(UINT msg,WPARAM wparam,LPARAM LPARAM);
……
……
}
//初始化
BOOL CDlgSkinWin:安装皮肤(CWnd * wnd)
{
如果(!wnd !m_bInit)
返回错误的
//开始捕获此窗口的消息
//钩子窗口((HWND)NULL);
int r=挂钩窗口(wnd);
return r;
}
//消息处理函数
LRESULT CDlgSkin:window proc(UINT msg,WPARAM wp/*wparam*/,LPARAM lp/*lparam*/)
{
如果(!IsWindow(m_hWnd))
返回0;
如果(!m_bInit)
返回默认值();
开关(消息)
{
案例WM_SHOWWINDOW:
//当窗口句柄为对话框时,调用设置和获取窗口位置强制OnNcCalcSize
中频(可湿性粉剂)
SetWindowPos( m_hWnd,0,0,0,400,400,SWP _诺西泽SWP诺莫夫 SWP _帧已更改);
默认();
m _ down hittest=0;
m _ move hittest=0;
返回0;
打破;
//case WM_ERASEBKGND:
案例WM_INITMENUPOPUP:
默认();
返回0;
案例WM_SYSCOMMAND:
OnSysCommand( wp,LP);
返回0;
案例WM_SETTEXT:
return OnSetText( wp,LP);
案例WM_NCPAINT:
OnNcPaint((HRGN)WP);
返回0;
案例WM_NCCALCSIZE:
OnNcCalcSize( (BOOL)wp,(NCCALCSIZE _ PARAMS *)LP);
返回0;
案例WM_SIZE:
OnSize( wp,low word(LP),hi word(LP));
返回0;
案例WM _激活:
返回OnNcActivate((BOOL)WP);
案例WM_NCHITTEST:
return OnNcHitTest(c point(LOWORD(LP),hi word(LP)));
案例WM_NCLBUTTONUP:
OnNcLButtonUp(wp,CPoint(LOWORD(lp),hi word(LP)));
返回0;
案例WM_NCLBUTTONDOWN:
OnNcLButtonDown(wp,CPoint(LOWORD(lp),hi word(LP)));
返回0;
案例WM_NCLBUTTONDBLCLK:
OnNcLButtonDblClk(wp,c point(low word(LP),hi word(LP));
返回0;
案例WM_NCRBUTTONUP:
OnNcRButtonUp(wp,CPoint(LOWORD(lp),hi word(LP)));
返回0;
案例WM_NCRBUTTONDOWN:
OnNcRButtonDown(wp,CPoint(LOWORD(lp),hi word(LP)));
返回0;
案例WM_NCMOUSEMOVE:
OnNcMouseMove( wp,CPoint(LOWORD(lp),hi word(LP)));
返回0;
案例WM_GETMINMAXINFO:
OnGetMinMaxInfo((MINMAXINFO *)LP);
返回0;
案例WM_WINDOWPOSCHANGING:
OnWindowPosChanging((WINDOWPOS *)LP);
返回0;
案例WM_SIZING:
OnSizing( wp,(LPRECT)LP);
返回0;
案例WM_ACTIVATE:
OnActivate( wp,CWnd:FromHandle((HWND)lp),0);
返回0;
案例WM _命令:
如果(!HandleSysCommand( wp,lp))
默认();
返回0;
默认值:
返回默认值();
}
}
简单的调用方法:
B类:公共A
{
……
}
一个
电子商务
HWND ha=a . GetSafeHwnd();
b .子类窗口(ha);#当然A和B不一定是继承关系。
注意:在被子类化的窗口销毁之前,必须执行窗口的反子类化:
b.UnSubclassWindow();
子类化跟超类化的区别:
超类化:首先获得一个已存在的窗口类,然后设置窗口类,最后注册该窗口类。
如:
WNDCLASSEX wc
WC . CB size=sizeof(WC);//由//Windows用于版本检查,不考虑窗口特征。
GetClassInfoEx(hinst," XXXXXX ",WC);
//hinst—定义窗口类XXXXXX的模块的句柄,比如系统定义的窗口类(如EDIT,BUTTON),hinst=NULL。
WC . lpsz class name=" yyyyyy ";//必须更改窗口类的名称
WC . hbrbackground=CreateSolidBrush(RGB(0,0.0));//更改背景画笔
wc.lpfnWndProc=NewWndProc//改变窗口功能
……
register classex(WC);//注册新的窗口类
//使用窗口类
……
* create window(_ T(" YYYYYYYY ",……);
因此,超分类只能改变自己创建的窗口的特性,而不能用于创建的窗口;
但是,子类化是在实例级别。只要能得到窗口的句柄,就可以子类化,这也是子类化比超类化的一个优势。
摘要
(0)子类化窗口过程函数,超类化窗口类(新窗口类名)
(1)子类化在窗口实例级别,超类化在窗口类(WNDCLASS)级别。
(2)超分类比子类化能完成更复杂的功能。在SDK类别中,子类化可以被认为是超分类的子集。
(3)子类化只能改变窗口创建后的性质,但在窗口创建过程中不能做任何事情(ON_CREATE事件不能被拦截),而超类化可以实现;超分类不能用于创建的窗口,但子类化可以。
来自:http://blog . . net/Lin _ angle/article/details/6178351