CWnd中PreCreateWindow、PreSubclassWindow、SubclassWindow的区别
http://blog.csdn.net/swimmer2000/archive/2007/10/30/1856213.aspx
MFC(VC6.0)的CWnd及其子类中,有如下三个函数:
 // From VS Install PathVC98MFCIncludeAFXWIN.H
    // From VS Install PathVC98MFCIncludeAFXWIN.H class CWnd : public CCmdTarget
    class CWnd : public CCmdTarget {
    { ...
        ... public:
    public: ...
        ... virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
        virtual BOOL PreCreateWindow(CREATESTRUCT& cs); virtual void PreSubclassWindow();
        virtual void PreSubclassWindow(); BOOL SubclassWindow(HWND hWnd);
        BOOL SubclassWindow(HWND hWnd); ...
        ... };
    }; 
    
让人很不容易区分,不知道它们究竟干了些什么,在什么情况下要改写哪个函数?
想知道改写函数?让我先告诉你哪个不能改写,那就是SubclassWindow。Scott Meyers的杰作<<Effective C++>>的第36条是这样的:Differentiate between inheritance of interface and inheritance of implementation. 看了后你马上就知道,父类中的非虚拟函数是设计成不被子类改写的。根据有无virtual关键字,我们在排除了SubclassWindow后,也就知道PreCreateWindow和PreSubClassWindow是被设计成可改写的。接着的问题便是该在什么时候该写了。要知道什么时候该写,必须知道函数是在什么时候被调用,还有执行函数的想要达到的目的。我们先看看对这三个函数,MSDN给的解释:
    
    PreCreateWindow:
    
        Called by the framework before the creation of the Windows window 
        attached to this CWnd object.
        (译:在窗口被创建并attach到this指针所指的CWnd对象之前,被framework调用)
        
    PreSubclassWindow:
    
        This member function is called by the framework to allow other necessary 
        subclassing to occur before the window is subclassed.
        (译:在window被subclassed之前被framework调用,用来允许其它必要的
            subclassing发生)
            
虽然我已有译文,但还是让我对CWnd的attach和窗口的subclass作简单的解释吧!要理解attach,我们必须要知道一个C++的CWnd对象和窗口(window)的区别:window就是实在的窗口,而CWnd就是MFC用类对window所进行C++封装。attach,就是把窗口附加到CWnd对象上操作。附加(attach)完成后,CWnd对象才和窗口发生了联系。窗口的subclass是指修改窗口过程的操作,而不是面向对象中的派生子类。
好了,PreCreateWindow由framework在窗口创建前被调用,函数名也说明了这一点,Pre应该是previous的缩写,PreSubclassWindow由framework在subclass窗口前调用。 这段话说了等于没说,你可能还是不知道,什么时候该改写哪个函数。罗罗嗦嗦的作者,还是用代码说话吧!源码之前,了无秘密(候捷语)。我们就看看MFC中的这三个函数都是这样实现的吧!
 // From VS Install PathVC98MFCSRCWINCORE.CPP
    // From VS Install PathVC98MFCSRCWINCORE.CPP BOOL CWnd::CreateEx(DWORD dwExStyle, LPCTSTR lpszClassName,
    BOOL CWnd::CreateEx(DWORD dwExStyle, LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle,
 LPCTSTR lpszWindowName, DWORD dwStyle, int x, int y, int nWidth, int nHeight,
 int x, int y, int nWidth, int nHeight, HWND hWndParent, HMENU nIDorHMenu, LPVOID lpParam)
 HWND hWndParent, HMENU nIDorHMenu, LPVOID lpParam) {
    { // allow modification of several common create parameters
     // allow modification of several common create parameters CREATESTRUCT cs;
     CREATESTRUCT cs; cs.dwExStyle = dwExStyle;
     cs.dwExStyle = dwExStyle; cs.lpszClass = lpszClassName;
     cs.lpszClass = lpszClassName; cs.lpszName = lpszWindowName;
     cs.lpszName = lpszWindowName; cs.style = dwStyle;
     cs.style = dwStyle; cs.x = x;
     cs.x = x; cs.y = y;
     cs.y = y; cs.cx = nWidth;
     cs.cx = nWidth; cs.cy = nHeight;
     cs.cy = nHeight; cs.hwndParent = hWndParent;
     cs.hwndParent = hWndParent; cs.hMenu = nIDorHMenu;
     cs.hMenu = nIDorHMenu; cs.hInstance = AfxGetInstanceHandle();
     cs.hInstance = AfxGetInstanceHandle(); cs.lpCreateParams = lpParam;
     cs.lpCreateParams = lpParam; 
     if (!PreCreateWindow(cs))
     if (!PreCreateWindow(cs)) {
     { PostNcDestroy();
      PostNcDestroy(); return FALSE;
      return FALSE; }
     } 
     AfxHookWindowCreate(this);
     AfxHookWindowCreate(this); HWND hWnd = ::CreateWindowEx(cs.dwExStyle, cs.lpszClass,
     HWND hWnd = ::CreateWindowEx(cs.dwExStyle, cs.lpszClass, cs.lpszName, cs.style, cs.x, cs.y, cs.cx, cs.cy,
       cs.lpszName, cs.style, cs.x, cs.y, cs.cx, cs.cy, cs.hwndParent, cs.hMenu, cs.hInstance, cs.lpCreateParams);
       cs.hwndParent, cs.hMenu, cs.hInstance, cs.lpCreateParams); 
     ...
        ... return TRUE;
     return TRUE; }
    } 
     // for child windows
    // for child windows BOOL CWnd::PreCreateWindow(CREATESTRUCT& cs)
    BOOL CWnd::PreCreateWindow(CREATESTRUCT& cs) {
    { if (cs.lpszClass == NULL)
     if (cs.lpszClass == NULL) {
     { // make sure the default window class is registered
      // make sure the default window class is registered VERIFY(AfxDeferRegisterClass(AFX_WND_REG));
      VERIFY(AfxDeferRegisterClass(AFX_WND_REG)); 
     // no WNDCLASS provided - use child window default
      // no WNDCLASS provided - use child window default ASSERT(cs.style & WS_CHILD);
      ASSERT(cs.style & WS_CHILD); cs.lpszClass = _afxWnd;
      cs.lpszClass = _afxWnd; }
     } return TRUE;
     return TRUE; }
    }

CWnd::CreateEx先设定cs(CREATESTRUCT),在调用真正的窗口创建函数::CreateWindowEx之前,调用了CWnd::PreCreateWindow函数,并把参数cs以引用的方式传递了进去。而CWnd的PreCreateWindow函数也只是给cs.lpszClass赋值而已。毕竟,窗口创建函数CWnd::CreateEx的诸多参数中,并没有哪个指定了所要创建窗口的窗口类,而这又是不可缺少的(请参考<<windows程序设计>>第三章)。所以当你需要修改窗口的大小、风格、窗口所属的窗口类等cs成员变量时,要改写PreCreateWindow函数。
 // From VS Install PathVC98MFCSRCWINCORE.CPP
    // From VS Install PathVC98MFCSRCWINCORE.CPP BOOL CWnd::SubclassWindow(HWND hWnd)
    BOOL CWnd::SubclassWindow(HWND hWnd) {
    { if (!Attach(hWnd))
     if (!Attach(hWnd)) return FALSE;
      return FALSE; 
     // allow any other subclassing to occur
     // allow any other subclassing to occur PreSubclassWindow();
     PreSubclassWindow(); 
     // now hook into the AFX WndProc
     // now hook into the AFX WndProc WNDPROC* lplpfn = GetSuperWndProcAddr();
     WNDPROC* lplpfn = GetSuperWndProcAddr(); WNDPROC oldWndProc = (WNDPROC)::SetWindowLong(hWnd, GWL_WNDPROC,
     WNDPROC oldWndProc = (WNDPROC)::SetWindowLong(hWnd, GWL_WNDPROC, (DWORD)AfxGetAfxWndProc());
      (DWORD)AfxGetAfxWndProc()); ASSERT(oldWndProc != (WNDPROC)AfxGetAfxWndProc());
     ASSERT(oldWndProc != (WNDPROC)AfxGetAfxWndProc()); 
     if (*lplpfn == NULL)
     if (*lplpfn == NULL) *lplpfn = oldWndProc;   // the first control of that type created
      *lplpfn = oldWndProc;   // the first control of that type created #ifdef _DEBUG
    #ifdef _DEBUG else if (*lplpfn != oldWndProc)
     else if (*lplpfn != oldWndProc) {
     { ...
      ... ::SetWindowLong(hWnd, GWL_WNDPROC, (DWORD)oldWndProc);
      ::SetWindowLong(hWnd, GWL_WNDPROC, (DWORD)oldWndProc); }
     } #endif
    #endif 
     return TRUE;
     return TRUE; }
    }
 void CWnd::PreSubclassWindow()
    void CWnd::PreSubclassWindow() {
    { // no default processing
     // no default processing }
    }

CWnd::SubclassWindow先调用函数Attach(hWnd)让CWnd对象和hWnd所指的窗口发生关联。接着在用::SetWindowLong修改窗口过程(subclass)前,调用了PreSubclassWindow。CWnd::PreSubclassWindow则是什么都没有做。
在CWnd的实现中,除了CWnd::SubclassWindow会调用PreSubclassWindow外,还有一处。上面所列函数CreateEx的代码,其中调用了一个AfxHookWindowCreate函数,见下面代码:
 // From VS Install PathVC98MFCSRCWINCORE.CPP
    // From VS Install PathVC98MFCSRCWINCORE.CPP BOOL CWnd::CreateEx(...)
    BOOL CWnd::CreateEx(...) {
    { // allow modification of several common create parameters
     // allow modification of several common create parameters ...
        ... 
     if (!PreCreateWindow(cs))
     if (!PreCreateWindow(cs)) {
     { PostNcDestroy();
      PostNcDestroy(); return FALSE;
      return FALSE; }
     } 
     AfxHookWindowCreate(this);
     AfxHookWindowCreate(this);  HWND hWnd = ::CreateWindowEx(cs.dwExStyle, cs.lpszClass,
     HWND hWnd = ::CreateWindowEx(cs.dwExStyle, cs.lpszClass, cs.lpszName, cs.style, cs.x, cs.y, cs.cx, cs.cy,
       cs.lpszName, cs.style, cs.x, cs.y, cs.cx, cs.cy, cs.hwndParent, cs.hMenu, cs.hInstance, cs.lpCreateParams);
       cs.hwndParent, cs.hMenu, cs.hInstance, cs.lpCreateParams); 
     ...
        ... return TRUE;
     return TRUE; }
    }
接着察看AfxHookWindowCreate的代码:
 // From VS Install PathVC98MFCSRCWINCORE.CPP
    // From VS Install PathVC98MFCSRCWINCORE.CPP void AFXAPI AfxHookWindowCreate(CWnd* pWnd)
    void AFXAPI AfxHookWindowCreate(CWnd* pWnd) {
    { ...
     ... 
     if (pThreadState->m_hHookOldCbtFilter == NULL)
     if (pThreadState->m_hHookOldCbtFilter == NULL) {
     { pThreadState->m_hHookOldCbtFilter = ::SetWindowsHookEx(WH_CBT,
      pThreadState->m_hHookOldCbtFilter = ::SetWindowsHookEx(WH_CBT, _AfxCbtFilterHook, NULL, ::GetCurrentThreadId());
       _AfxCbtFilterHook, NULL, ::GetCurrentThreadId()); if (pThreadState->m_hHookOldCbtFilter == NULL)
      if (pThreadState->m_hHookOldCbtFilter == NULL) AfxThrowMemoryException();
       AfxThrowMemoryException(); }
     } ...
     ... }
    }
其主要作用的::SetWindowsHookEx函数用于设置一个挂钩函数(Hook函数)_AfxCbtFilterHook,每当Windows产生一个窗口时(还有许多其它类似,请参考<<深入浅出MFC>>第9章,563页),就会调用你设定的Hook函数。
这样设定完成后,回到CWnd::CreateEx函数中,执行::CreateWindowEx进行窗口创建,窗口一产生,就会调用上面设定的Hook函数_AfxCbtFilterHook。而正是在_AfxCbtFilterHook中对函数PreSubclassWindow进行了第二次调用。见如下代码:
 // From VS Install PathVC98MFCSRCWINCORE.CPP
    // From VS Install PathVC98MFCSRCWINCORE.CPP /////////////////////////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////// // Window creation hooks
    // Window creation hooks 
     LRESULT CALLBACK
    LRESULT CALLBACK _AfxCbtFilterHook(int code, WPARAM wParam, LPARAM lParam)
    _AfxCbtFilterHook(int code, WPARAM wParam, LPARAM lParam) {
    { ...
            ...        ...
                 ... // connect the HWND to pWndInit...
        // connect the HWND to pWndInit... pWndInit->Attach(hWnd);
      pWndInit->Attach(hWnd); // allow other subclassing to occur first
        // allow other subclassing to occur first pWndInit->PreSubclassWindow();
        pWndInit->PreSubclassWindow(); ...
                ... {
        { // subclass the window with standard AfxWndProc
                // subclass the window with standard AfxWndProc oldWndProc = (WNDPROC)SetWindowLong(hWnd, GWL_WNDPROC, (DWORD)afxWndProc);
                oldWndProc = (WNDPROC)SetWindowLong(hWnd, GWL_WNDPROC, (DWORD)afxWndProc); ASSERT(oldWndProc != NULL);
            ASSERT(oldWndProc != NULL); *pOldWndProc = oldWndProc;
                *pOldWndProc = oldWndProc; }
        } ...
           ... }
    }
也在调用函数SetWindowLong进行窗口subclass前调用了PreSubclassWindow.
http://blog.csdn.net/xiexievv/article/details/6233423
CWnd中PreCreateWindow、PreSubclassWindow、SubclassWindow的区别的更多相关文章
- CWnd中PreCreateWindow、PreSubclassWindow、SubclassWindow
		原文链接:http://blog.chinaunix.net/uid-14607221-id-2794642.html 1. PreCreateWindow: Called by the framew ... 
- MFC:OnCreate PreCreateWindow PreSubclassWindow
		OnCreate PreCreateWindow PreSubclassWindow PreCreateWindow和PreSubclassWindow是虚函数,而OnCreate是一个消息响应函数. ... 
- 【转】为什么我们都理解错了HTTP中GET与POST的区别
		GET和POST是HTTP请求的两种基本方法,要说它们的区别,接触过WEB开发的人都能说出一二. 最直观的区别就是GET把参数包含在URL中,POST通过request body传递参数. 你可能自己 ... 
- Visual Studio 中 Build 和 Rebuild 的区别
		因为之前写的程序比较小,编译起来比较快,所以一直都没有太在意 Build 和 Rebuild 之间的区别,后来发现两个还是有很大不同. Build 只针对在上次编译之后更改过的文件进行编译,在项目比较 ... 
- SQL Server 中 EXEC 与 SP_EXECUTESQL 的区别
		SQL Server 中 EXEC 与 SP_EXECUTESQL 的区别 MSSQL为我们提供了两种动态执行SQL语句的命令,分别是 EXEC 和 SP_EXECUTESQL ,我们先来看一下两种方 ... 
- java集合中List与set的区别
		java集合中List与set的区别. List可以存储元素为有序性并且元素可以相同. set存储元素为无序性并且元素不可以相同. 下面贴几段代码感受一下: ArrayL ... 
- Java中Set Map List 的区别
		java中set map list的区别: 都是集合接口 简要说明 set --其中的值不允许重复,无序的数据结构 list --其中的值允许重复,因为其为有序的数据结构 map--成对的数据结构 ... 
- oracle中函数和存储过程的区别和联系【转载竹沥半夏】
		oracle中函数和存储过程的区别和联系[转载竹沥半夏] 在oracle中,函数和存储过程是经常使用到的,他们的语法中有很多相似的地方,但也有自己的特点.刚学完函数和存储过程,下面来和大家分享一下自己 ... 
- JS中isPrototypeOf 和hasOwnProperty 的区别          -------          js使用in和hasOwnProperty获取对象属性的区别
		JS中isPrototypeOf 和hasOwnProperty 的区别 1.isPrototypeOf isPrototypeOf是用来判断指定对象object1是否存在于另一个对象object2的 ... 
随机推荐
- GitHub的问题
			出现failed to publish the branch, 转自:http://blog.csdn.net/cucmakeit/article/details/29407329 (windows系 ... 
- Google Code Jam Round 1A 2015 Problem B. Haircut  二分
			Problem You are waiting in a long line to get a haircut at a trendy barber shop. The shop has B barb ... 
- Codeforces Round #254 (Div. 2)  DZY Loves Chemistry【并查集基础】
			一开始不知道题意是啥意思,迟放进去反应和后放进去反应有什么区别 对于第三组数据不是很懂,为啥312,132的组合是不行的 后来发现这是一道考察并查集的题目 QAQ 怒贴代码: #include < ... 
- 432B - Football Kit
			解题思路: 暴力绝对TLE 一个队伍穿主场球衣的次数 = 这个队伍的客场球衣颜色与其他队主场球衣颜色起冲突的次数 + (n - 1) #include <stdio.h> #include ... 
- 用C语言打印出三角函数
			在网上看到一个实例,是用C 中的* 打印出三角函数cos #include<stdio.h> #include<math.h> int main() { double y; i ... 
- 基于visual Studio2013解决C语言竞赛题之0603打印素数
			 题目 
- partial_sort_百度百科
			partial_sort_百度百科 partial_sort 
- 原生app与web app的比较
			http://www.2ee9.com/news/news_show_36_237.html http://zhidao.baidu.com/link?url=7lWq2tgqiMiDmsRd54hO ... 
- HDU1005(周期问题)
			Description A number sequence is defined as follows: f(1) = 1, f(2) = 1, f(n) = (A * f(n - 1) + B * ... 
- Java 判断多级路径是否存在,不存在就创建
			第一种方案: /** * 是否创建目录 * @param path * @return */ public boolean isexitsPath(String path)throws Interru ... 
