none
Debug Assertion Failed While Subclassing MDIClient Window VC++ 2008

    Question

  • I'm an old dog trying to learn something new (to me)...

    My intent was to change the main window background in a MDI application using MFC. I followed the steps noted in Article 103786 and Article 129471, which include deriving a class CMDIClientWnd from CWnd, adding a member variable m_wndMDIClient to CMainFrame, and modifying the OnCreate function of CMainFrame with

    if (!m_wndMDIClient.SubclassWindow (m_hWndMDIClient))
    {
         TRACE ("Failed to subclass MDI client window\n");
                  return (-1);
    }
    

    When I build and run the application, I receive an error:

    Debug Assertion Failed

    wincore.cpp
    Line 330

    The line in wincore.cpp is as follows

    ASSERT(FromHandlePermanent(hWndNew) == NULL );

    I have learned from Article ID 113421 that the failure "implies that the MDIClient window has already been subclassed."

    I would like to fix the error and understand why it occurs.

    My latest suspicion is that the problem lies in the LoadFrame function inserted by the VS 2008 Wizard.

    Any ideas?
    Thursday, July 16, 2009 5:16 PM

Answers

  • I used the wizard to create a new MFC Application, and I selected 'Use a ribbon' as the User Interface Feature. Once again, if I created a new class CMDIClientWnd and tried to subclass the MDIClient window as described above, I received the 'Debug Assertion Failed' error after building and running the application.

    It appears to me that the steps desribed in Article 129471 and Article 103786 are not necessary with VC++ 2008. I was able to change the background color of the main frame window by overriding the OnEraseMDIClientBackground function in the CMainFrm class, which is possible because the CMainFrm class is derived from CMDIFrameWndEx. The code I used was as follows.

    In the MainFrm.h file

    // Overrides
    public:
         BOOL OnEraseMDIClientBackground(CDC* pDC);

    And in the MainFrm.cpp file I added

    // Override of member function to process WM_ERASEBKGND message in a CMDIFrameWndEx derived class
    
    BOOL CMainFrame::OnEraseMDIClientBackground(CDC* pDC)
    {
          // Brush for background color
         CBrush backBrush(RGB(255,0,0);
    
         // Save old brush
        CBrush* pOldBrush = pDC->SelectObject(&backBrush);
    
        CRect rect;
        pDC->GetClipBox(&rect);   // Erase the area
        pDC->PatBlt(rect.left, rect.top, rect.Width(), rect.Height(),PATCOPY);
        pDC->SelectObject(pOldBrush);
        return TRUE;
    }
    The result was as desired, that is, the main frame background is now red.
    • Marked as answer by DrBubba Thursday, July 16, 2009 9:03 PM
    Thursday, July 16, 2009 9:03 PM

All replies

  • I've learned and am including some additional information...

    When building a MFC Application, the Wizard (VS 2008) gives several options for User Interface Features. If I select the options 'Use a menu bar and a toolbar', 'User-defined toolbars and images', and 'Personalized Menu Behavior', the Wizard will declare a CMainFrame member function
    public:
       virtual BOOL LoadFrame(UINT nIDResource, DWORD dwDefaultStyle = WS_OVERLAPPEDWINDOW | FWS_ADDTOTITLE, CWnd* pParentWnd = NULL, CCreateContext* pContext = NULL);
    The CMainFrame::LoadFrame function is then defined as

    BOOL CMainFrame::LoadFrame(UINT nIDResource, DWORD dwDefaultStyle, CWnd* pParentWnd, CCreateContext* pContext)
    {
       // base class does the real work
    
       if (!CMDIFrameWndEx::LoadFrame(nIDResource, dwDefaultStyle, pParentWnd, pContext))
       {
             return FALSE;
       }
    
      // enable customization button for all user toolbars
      BOOL bNameValid;
      CString strCustomize;
      bNameValid = strCustomize.LoadString(IDS_TOOLBAR_CUSTOMIZE);
      ASSERT(bNameValid);
    
       for (int i = 0; 1 < iMaxUserToolbars; i++);
       {
            CMFCToolBar* pUserToolbar = GetUserToolBarByIndex(i);
            if (pUserToolBar != NULL)
            {
                  pUserToolbar->EnableCustomizeButton(TRUE, ID_VIEW_CUSTOMIZE, strCustomize);
            }
        }
    }
    Consequently, the 'Debug Assertion Failed' error occurs when I use m_wndMDIClient.SubClassWindow(m_hWndMDIClient). (See first post)

    HOWEVER, if I select 'Use a classic menu' and 'Use a classic docking toolbar' from the User Interface Features of the Wizard, the application builds and runs without error.

    Will the LoadFrame function above cause the 'Debug Assertion Failed' error when I try to subclass the MDIClient window?
    Thursday, July 16, 2009 7:00 PM
  • I used the wizard to create a new MFC Application, and I selected 'Use a ribbon' as the User Interface Feature. Once again, if I created a new class CMDIClientWnd and tried to subclass the MDIClient window as described above, I received the 'Debug Assertion Failed' error after building and running the application.

    It appears to me that the steps desribed in Article 129471 and Article 103786 are not necessary with VC++ 2008. I was able to change the background color of the main frame window by overriding the OnEraseMDIClientBackground function in the CMainFrm class, which is possible because the CMainFrm class is derived from CMDIFrameWndEx. The code I used was as follows.

    In the MainFrm.h file

    // Overrides
    public:
         BOOL OnEraseMDIClientBackground(CDC* pDC);

    And in the MainFrm.cpp file I added

    // Override of member function to process WM_ERASEBKGND message in a CMDIFrameWndEx derived class
    
    BOOL CMainFrame::OnEraseMDIClientBackground(CDC* pDC)
    {
          // Brush for background color
         CBrush backBrush(RGB(255,0,0);
    
         // Save old brush
        CBrush* pOldBrush = pDC->SelectObject(&backBrush);
    
        CRect rect;
        pDC->GetClipBox(&rect);   // Erase the area
        pDC->PatBlt(rect.left, rect.top, rect.Width(), rect.Height(),PATCOPY);
        pDC->SelectObject(pOldBrush);
        return TRUE;
    }
    The result was as desired, that is, the main frame background is now red.
    • Marked as answer by DrBubba Thursday, July 16, 2009 9:03 PM
    Thursday, July 16, 2009 9:03 PM
  • Those (very old) articles only apply to CMDIFrameWnd apps. Anything that uses the MFC Feature Pack will be using CMDIFrameWndEx which is a very different beast. It has this feature built it as you've found out.

    Also, as you've already surmised, CMDIFrameWndEx has already subclassed the client area:

    <afxmdiframewndex.cpp>
    BOOL CMDIFrameWndEx::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext)
    {
     if (!CMDIFrameWnd::OnCreateClient(lpcs, pContext))
     {
      return FALSE;
     }

     if (m_bDoSubclass)
     {
      m_wndClientArea.SubclassWindow(m_hWndMDIClient);
     }

     return TRUE;
    }

    If you were able to subclass the Ex client area, you'd probably end up breaking a lot of the FluentUI features - take a browse of the AfxMDIClientAreaWnd.cpp implementation file.

    Steve Horne
    Microsoft

    • Proposed as answer by tibb Saturday, October 15, 2011 4:28 PM
    Friday, July 17, 2009 3:17 AM