1.当用SubClass的方法,使一个CWnd的类与一个HWND的句柄联系在一起之后,CWnd的类会首先调用这个函数进行预先的处理,你可以重载以便处理自己的要预先准备的数据!
子类化:就是将一个HWND的句柄中的WndProc用SetWindowLong的方法替换为由CWnd的AfxWndProc;然后用类的方法处理HWND;2.是WINDOW在绘制时的有效区域,可以自己改动大小!3.当有一些消息需要在传递给消息处理函数之前,先作些处理时就可以用,不过也经常有一些需要监测消息的功能和其他一些自定义的功能需要在这里处理!
直接通过ClassWizard就可进行重载,也可手工添加:
//在.h文件的class 声明中添加;
virtual BOOL PreTranslateMessage(MSG* pMsg);
//在.cpp文件中添加函数体:BOOL CMyWnd::PreTranslateMessage(MSG* pMsg) 
{
    // TODO: Add your specialized code here and/or call the base class    return CBaseWnd::PreTranslateMessage(pMsg);
}4.当你不想让窗口用缺省的方式(DefWindowProc)绘制底色的时,就重载!
直接通过ClassWizard响应WM_ERASEBKGND即可;
或者手工:
//在.h文件的class 声明中添加
afx_msg BOOL OnEraseBkgnd(CDC* pDC);
//在.cpp文件的消息映射表中添加
BEGIN_MESSAGE_MAP(CMyWnd, CBaseWnd)
...
ON_WM_ERASEBKGND() // 添加的行
...
END_MESSAGE_MAP()
//在.cpp中添加函数;
BOOL CMyWnd::OnEraseBkgnd(CDC* pDC) 
{
    // TODO: Add your message handler code here and/or call default
    return CBaseWnd::OnEraseBkgnd(pDC);
}5.直接的效果就是使TextOut,DrawText等文字输出函数的在该DC上输出的文字没有文字的背景,只有文字的颜色!同时生效的还有网格画刷!对某些类型的Pen也有类似效果!6.是用来判断鼠标的位置处于WINDOWS的哪个位置,比如:
是否Window的Caption?
是否Window的Border(上下左右)?
是否Window的Client Region?
是否Window的左上角,右下角...
等!

解决方案 »

  1.   

    1.自己懒得写,在MSDN中搜索SubclassWindow在Knowledge base中找到几个例子,其一:
    HOWTO: SubClass the MDIClient by Using MFC
    Last reviewed: October 23, 1998
    Article ID: Q129471 
    --------------------------------------------------------------------------------The information in this article applies to: 
    The Microsoft Foundation Classes (MFC) included with: 
        - Microsoft Visual C++ for Windows, versions 1.0, 1.5, 1.51, 1.52
        - Microsoft Visual C++, 32-bit Edition, versions 1.0, 2.0, 2.1,
          4.0, 4.1, 4.2, 5.0, 6.0
    SUMMARY
    In MFC, the MDICLIENT window is stored in a public HWND member variable (m_hwndMDIClient) within the CMDIFrameWnd class. CMDIFrameWnd is the base class of the CMainFrame class in an AppWizard-generated MDI application. There are three steps required to subclass the MDICLIENT window: 
    Use ClassWizard to derive a class from CWnd called CMDIClientWnd. Add the function, GetSuperWndProcAddr(), to CMDIClientWnd. Use CMDIClientWnd to subclass the MDICLIENT window. Once the MDICLIENT window has been subclassed with CMDIClientWnd, message handlers and other functions can be placed in the CMDIClientWnd class. 
    MORE INFORMATION
    Here is more detailed information about each of the steps: 
    Use ClassWizard to derive a class from CWnd called CMDIClientWnd. 
    For details on how to derive a class using ClassWizard, please see the User's Guide documentation on ClassWizard, specifically the "Adding a New Class" section. 
    Add the function GetSuperWndProcAddr() to CMDIClientWnd. 
    NOTE: This step need only be performed if you are using 16-bit versions of Visual C++, not 32-bit. The 32-bit versions of Visual C++ implement this functionality for you. Once the class has been created, add the following prototype to the header file:       public:
              WNDPROC* GetSuperWndProcAddr();   And add the following function to the .CPP file:      WNDPROC* CMDIClientWnd::GetSuperWndProcAddr() {
              static WNDPROC NEAR pfnSuper = NULL;
              return &pfnSuper;
          }Use CMDIClientWnd to subclass the MDICLIENT window in the CMDIFrameWnd class (usually CMainFrame). 
    To the CMainFrame class, add a public variable of type CMDIClientWnd called m_wndMDIClient. Then modify OnCreate for CMainFrame as follows:       int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
          {
              if (CMDIFrameWnd::OnCreate(lpCreateStruct) == -1)
              return -1;          if (!m_wndMDIClient.SubclassWindow (m_hWndMDIClient)) { // Add
                  TRACE ("Failed to subclass MDI client window\n");   // Add
                  return (-1);                                        // Add
              }                                                       // Add
          ...
          }
    After completing these three steps, you can use ClassWizard to add message handlers to CMDIClientWnd similar to the one below, which changes the MDICLIENT's background color. 
    BOOL CMDIClientWnd::OnEraseBkgnd(CDC* pDC) {   // Set brush to desired background color
      CBrush backBrush(RGB(255, 128, 128));  // Save old brush
      CBrush* pOldBrush = pDC->SelectObject(&backBrush);  CRect rect;
      pDC->GetClipBox(&rect);     // Erase the area needed  pDC->PatBlt(rect.left, rect.top, rect.Width(), rect.Height(),
          PATCOPY);
      pDC->SelectObject(pOldBrush);
      return TRUE;} Keywords          : MfcMisc kbvc600 kbvc500 kbvc410 kbvc420 kbvc100 kbvc150 kbvc152 kbvc200 kbMFC kbprg kbtool
    Technology        : kbMfc
    Version           : 1.0 1.5 1.52 2.0 4.1 4.2 5.0 6.0
    Platform          : NT WINDOWS
    Issue type        : kbhowto
     --------------------------------------------------------------------------------
    ================================================================================
    THE INFORMATION PROVIDED IN THE MICROSOFT KNOWLEDGE BASE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. MICROSOFT DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR IMPLIED, INCLUDING THE WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL MICROSOFT CORPORATION OR ITS SUPPLIERS BE LIABLE FOR ANY DAMAGES WHATSOEVER INCLUDING DIRECT, INDIRECT, INCIDENTAL, CONSEQUENTIAL, LOSS OF BUSINESS PROFITS OR SPECIAL DAMAGES, EVEN IF MICROSOFT CORPORATION OR ITS SUPPLIERS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. SOME STATES DO NOT ALLOW THE EXCLUSION OR LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES SO THE FOREGOING LIMITATION MAY NOT APPLY.  Last reviewed: October 23, 1998
    © 1998 Microsoft Corporation. All rights reserved. Terms of Use.
      

  2.   

    2.最简单的应用!
    void CMyView::OnDraw(CDC* pDC)
    {
        CRgn rgnNew;
        //获得指定的rgn,实际应用中可将rgn的获得通过函数封装起来,以便更具有灵活性!
        rgnNew.CreateRectRgn(10, 10, 300, 100);    //将得到的rgn用RGN_COPY的方式选择到当前的DC中,就使的所有不再这个rgn区域内的绘制代码都无效,看不到!
        //当然如果使用RGN_AND,RGN_XOR,RGN_OR,RGN_DIFF等就会有不同的效果!
        pDC->SelectClipRgn(&rgnNew, RGN_COPY);
        rgnNew.DeleteObject();
    }
    当然上述的代码也可以在一次绘制的过程中不断的变动Rgn,不断的进行SelectClipRgn的动作,以产生更灵活的应用!3.比如给当前的窗口(CMyWnd)添加加速键的处理!
    int CMyWnd::OnCreate(LPCREATESTRUCT lpCreateStruct)
    {
        ...
        m_hAccel = ::LoadAccelerators(hCurrentInst, IDR_MYACCEL);
        ...
    }
    BOOL CMyWnd::PreTranslateMessage(MSG* pMsg) 
    {
        // TODO: Add your specialized code here and/or call the base class
        if(m_hAccel)
        {
            if(::TranslateAccelerator(GetSafeHwnd(), m_hAccel, pMsg))
                return TRUE;
        }
        return CBaseWnd::PreTranslateMessage(pMsg);
    }4.
    BOOL CMyWnd::OnEraseBkgnd(CDC* pDC) 
    {
        // TODO: Add your message handler code here and/or call default
        return TRUE;//返回TRUE,不再继续擦WINDOW的背景!
    //    return CBaseWnd::OnEraseBkgnd(pDC);
    }5.void CMyView::OnDraw(CDC* pDC)
    {
        ...
        CString strOutput("Text output!");
        pDC->TextOut(10, 10, strOutput);
        pDC->SetBkMode(TRANSPARENT);
        pDC->TextOut(10, 100, strOutput);
        //两次的效果不同;
        ...
    }6.在MSDN中搜索OnNcHittest关键字,在C++Q&A中找到的例子!
    Figure 13 Fixing the Buggy Title Bar
    ////////////////////////////////////////////////////////////////
    // Copyright 1996 Microsoft Systems Journal. 
    // If this program works, it was written by Paul DiLascia.
    // If not, I don't know who wrote it.
    // This program compiles with Visual C++ 4.1 on Windows 95
    //
    // MONITOR shows how to create a main window that is only a title bar,
    // and how to prevent Windows from drawing size cursors in up/down or
    // left/right directions
    //
    #include "StdAfx.h"
    #include "TraceWin.h"////////////////
    // Remove this comment to see the original bug
    //
    //#define BUG//////////////////
    // Standard application class
    //
    class CMonitorApp : public CWinApp {
    public:
       CMonitorApp() : CWinApp() { }
       virtual BOOL InitInstance();
    };//////////////////
    // Monitor window is main frame
    //
    class CMonitorWindow : public CFrameWnd {
    public:
       CMonitorWindow();
       afx_msg void OnTimer(UINT nIdEvent);
       afx_msg void OnPaint();
       afx_msg UINT OnNcHitTest(CPoint point);
       DECLARE_MESSAGE_MAP()   
    };          CMonitorApp theApp;//////////////////
    // Initialize app: create main window
    //
    BOOL CMonitorApp::InitInstance()
    {
       MfxTraceInit();
       m_pMainWnd = new CMonitorWindow;
       m_pMainWnd->ShowWindow(m_nCmdShow);
       m_pMainWnd->UpdateWindow();
       return TRUE;
    }   BEGIN_MESSAGE_MAP(CMonitorWindow, CFrameWnd)
       ON_WM_TIMER()
       ON_WM_PAINT()
       ON_WM_NCHITTEST()
    END_MESSAGE_MAP() //////////////////
    // Create monitor window. Constructor actually creates window too.
    //
    CMonitorWindow::CMonitorWindow()
    {
       // Compute size of window: smallest to display text
       CString s = _T("Memory: 100%% used [Phys:999999K total/999999K free]");
       CWindowDC dc(NULL);                            // screen DC
       CSize sz = dc.GetTextExtent(s, s.GetLength()); // size of text
       sz.cx += 2*GetSystemMetrics(SM_CXSMICON) +     // plus icon, close box,
          2*GetSystemMetrics(SM_CXSIZEFRAME);         // and sizable frame
       sz.cy += 2*GetSystemMetrics(SM_CYFIXEDFRAME);  // should be SIZEFRAME, but
                                                      // it doesn't matter
       CreateEx(WS_EX_TOPMOST, NULL, NULL,
    #ifdef BUG
          // The buggy version uses WS_BORDER to disallow sizing,
          // resulting in a frame that's too narrow.
          WS_BORDER 
    #else
          // The fix uses WS_THICKFRAME to get the fat border, but
          // disallows sizing by trapping WM_NCHITTEST
          WS_THICKFRAME
    #endif
          | WS_CAPTION | WS_SYSMENU,
          CW_USEDEFAULT,
          CW_USEDEFAULT,
          sz.cx,
          sz.cy,
          NULL, 0);   TRACE("Desired size = %d x %d\n", sz.cx, sz.cy);
       CRect rc;
       GetWindowRect(&rc);
       TRACE("Actual size  = %d x %d\n", rc.Width(), rc.Height());
       GetClientRect(&rc);
       TRACE("Client size  = %d x %d\n", rc.Width(), rc.Height());   TRACE("Minimum window height = %d\n",  GetSystemMetrics(SM_CYMIN));
       TRACE("Caption height = %d\n",         GetSystemMetrics(SM_CYCAPTION));
       TRACE("Sizable border height   = %d\n",GetSystemMetrics(SM_CYSIZEFRAME));
       TRACE("Non-sizable border height = %d\n",
          GetSystemMetrics(SM_CYFIXEDFRAME));   SetTimer((UINT) 1, (UINT) 7500, NULL);
       OnTimer(1); // first update immediately
    }//////////////////
    // Update the window caption by getting new memory stats
    //
    void CMonitorWindow::OnTimer(UINT nIdEvent)

       MEMORYSTATUS ms;
       ms.dwLength = sizeof(MEMORYSTATUS);
       GlobalMemoryStatus(&ms);
       CString s;
       s.Format(_T("Memory: %2ld%% used [Phys:%ldK total/%ldK free]"),
          ms.dwMemoryLoad,
          ms.dwTotalPhys>>10,
          ms.dwAvailPhys>>10);
       SetWindowText(s);
    }//////////////////
    // Handle WM_NCCHITTEST:
    // Re-map top/bottom to HTBORDER, and corners to HTLEFT or HTRIGHT
    //
    UINT CMonitorWindow::OnNcHitTest(CPoint point)
    {
       UINT nRet = CFrameWnd::OnNcHitTest(point);
    #ifndef BUG
       switch (nRet) {
       case HTTOP:
       case HTBOTTOM:
          return HTBORDER;
       case HTTOPLEFT:
       case HTBOTTOMLEFT:
          return HTLEFT;
       case HTTOPRIGHT:
       case HTBOTTOMRIGHT:
          return HTRIGHT;
       }
    #endif
       return nRet;
    }//////////////////
    // Paint client red to make it contrast more with frame/caption
    //
    void CMonitorWindow::OnPaint()
    {
       CPaintDC dc(this);
       CRect rc;
       GetClientRect(&rc);
       CBrush b(RGB(255,0,0)); // red
       CBrush* pOldBrush = dc.SelectObject(&b);
       dc.PatBlt(rc.left, rc.top, rc.Width(), rc.Height(), PATCOPY);
       dc.SelectObject(pOldBrush);
    }
      

  3.   

    holly谢谢你耐心的帮助!先送上50分!如果可以的话可否回答以下三个问题。1.如果我的一个程序依赖于第三方编写的dll(如www.codejoke.com提供的dll),如何使我的程序能够静态连接到该dll?如何使该dll能够在其他机器上自动注册?2.为何我在重载了OnCtlColor()后其他控件的颜色均改变了,但button的底色却未改变?我的代码是:
    HBRUSH CCtrlDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) 
    {
    HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);

    // TODO: Change any attributes of the DC here
    if (nCtlColor==CTLCOLOR_BTN ){
      static CBrush brush(RGB(20,90,123));
          pDC->SetBkColor(RGB(20,90,123));   
          pDC->SetTextColor(RGB(256,256,256));
      return HBRUSH(brush);
    }
    // TODO: Return a different brush if the default is not desired
    return hbr;
    }
    3.最后问一下,我的msdn中的mfc sample例子程序均不能安装,总是在“click to open or copy XXX project files"连接后,弹出插入msdn光盘的提示,但插入光盘后却"找不到帮助文件“。你的msdn例子程序能否运行?
      

  4.   

    holly太累了,我来试试:
    1.需要.lib文件(一般与.dll捆在一起),在setting->link->object/dll moudle上
    把它加入。
      在其它机器上,不需注册,但你需要与你的.exe捆在一起
    2.OnCtlColor()不能改变CButton的color,你需:
        class CMyButton::publi CButton;
    然後再重载CMyButton::DrawItem()来改变Color
    3.需要Copy到你的盘上
      

  5.   

    thanks killjapan,但是如何将dll与exe进行捆绑?
      

  6.   

    1.是否能静态链接,取决与你的第三方的库是否提供静态链接库文件(.lib),但并不是只要是.lib就可以静态链接,有些.lib只是为DLL准备的引出符号表!2.如Killjapan05所说!3.是否要注册也是有该DLL的特性决定的,普通的程序编写(没有COM的组件)可以不注册,只要DLL在系统的搜索路径中可以找到即可,但如果DLL中有COM组件,那么通常都需要注册,主要是CLSID和DLL本身的一些信息,这种DLL不注册是无法使用的!
      

  7.   

     thanks a lot!!!  holly you got another 30!! 20 to killjapan!! 
     hope will get your technical support again!! i am edwardyi!