home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / vc98 / mfc / src / winmdi.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1998-06-16  |  32.2 KB  |  1,161 lines

  1. // This is a part of the Microsoft Foundation Classes C++ library.
  2. // Copyright (C) 1992-1998 Microsoft Corporation
  3. // All rights reserved.
  4. //
  5. // This source code is only intended as a supplement to the
  6. // Microsoft Foundation Classes Reference and related
  7. // electronic documentation provided with the library.
  8. // See these sources for detailed information regarding the
  9. // Microsoft Foundation Classes product.
  10.  
  11. #include "stdafx.h"
  12.  
  13. #ifdef AFX_CORE4_SEG
  14. #pragma code_seg(AFX_CORE4_SEG)
  15. #endif
  16.  
  17. #ifdef _DEBUG
  18. #undef THIS_FILE
  19. static char THIS_FILE[] = __FILE__;
  20. #endif
  21.  
  22. /////////////////////////////////////////////////////////////////////////////
  23. // CMDIFrameWnd
  24.  
  25. BEGIN_MESSAGE_MAP(CMDIFrameWnd, CFrameWnd)
  26.     //{{AFX_MSG_MAP(CMDIFrameWnd)
  27.     ON_MESSAGE_VOID(WM_IDLEUPDATECMDUI, OnIdleUpdateCmdUI)
  28.     ON_UPDATE_COMMAND_UI(ID_WINDOW_ARRANGE, OnUpdateMDIWindowCmd)
  29.     ON_UPDATE_COMMAND_UI(ID_WINDOW_CASCADE, OnUpdateMDIWindowCmd)
  30.     ON_UPDATE_COMMAND_UI(ID_WINDOW_TILE_HORZ, OnUpdateMDIWindowCmd)
  31.     ON_UPDATE_COMMAND_UI(ID_WINDOW_TILE_VERT, OnUpdateMDIWindowCmd)
  32.     ON_WM_SIZE()
  33.     ON_COMMAND_EX(ID_WINDOW_ARRANGE, OnMDIWindowCmd)
  34.     ON_COMMAND_EX(ID_WINDOW_CASCADE, OnMDIWindowCmd)
  35.     ON_COMMAND_EX(ID_WINDOW_TILE_HORZ, OnMDIWindowCmd)
  36.     ON_COMMAND_EX(ID_WINDOW_TILE_VERT, OnMDIWindowCmd)
  37.     ON_UPDATE_COMMAND_UI(ID_WINDOW_NEW, OnUpdateMDIWindowCmd)
  38.     ON_COMMAND(ID_WINDOW_NEW, OnWindowNew)
  39.     ON_WM_DESTROY()
  40.     ON_MESSAGE(WM_COMMANDHELP, OnCommandHelp)
  41.     ON_WM_MENUCHAR()
  42.     //}}AFX_MSG_MAP
  43. END_MESSAGE_MAP()
  44.  
  45. CMDIFrameWnd::CMDIFrameWnd()
  46. {
  47.     m_hWndMDIClient = NULL;
  48. }
  49.  
  50. BOOL CMDIFrameWnd::OnCommand(WPARAM wParam, LPARAM lParam)
  51. {
  52.     // send to MDI child first - will be re-sent through OnCmdMsg later
  53.     CMDIChildWnd* pActiveChild = MDIGetActive();
  54.     if (pActiveChild != NULL && AfxCallWndProc(pActiveChild,
  55.       pActiveChild->m_hWnd, WM_COMMAND, wParam, lParam) != 0)
  56.         return TRUE; // handled by child
  57.  
  58.     if (CFrameWnd::OnCommand(wParam, lParam))
  59.         return TRUE; // handled through normal mechanism (MDI child or frame)
  60.  
  61.     HWND hWndCtrl = (HWND)lParam;
  62.  
  63.     ASSERT(AFX_IDM_FIRST_MDICHILD == 0xFF00);
  64.     if (hWndCtrl == NULL && (LOWORD(wParam) & 0xf000) == 0xf000)
  65.     {
  66.         // menu or accelerator within range of MDI children
  67.         // default frame proc will handle it
  68.         DefWindowProc(WM_COMMAND, wParam, lParam);
  69.         return TRUE;
  70.     }
  71.  
  72.     return FALSE;   // not handled
  73. }
  74.  
  75. BOOL CMDIFrameWnd::OnCmdMsg(UINT nID, int nCode, void* pExtra,
  76.     AFX_CMDHANDLERINFO* pHandlerInfo)
  77. {
  78.     CMDIChildWnd* pActiveChild = MDIGetActive();
  79.     // pump through active child FIRST
  80.     if (pActiveChild != NULL)
  81.     {
  82.         CPushRoutingFrame push(this);
  83.         if (pActiveChild->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
  84.             return TRUE;
  85.     }
  86.  
  87.     // then pump through normal frame
  88.     return CFrameWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);
  89. }
  90.  
  91. LRESULT CMDIFrameWnd::OnCommandHelp(WPARAM wParam, LPARAM lParam)
  92. {
  93.     if (lParam == 0 && IsTracking())
  94.         lParam = HID_BASE_COMMAND+m_nIDTracking;
  95.  
  96.     CMDIChildWnd* pActiveChild = MDIGetActive();
  97.     if (pActiveChild != NULL && AfxCallWndProc(pActiveChild,
  98.       pActiveChild->m_hWnd, WM_COMMANDHELP, wParam, lParam) != 0)
  99.     {
  100.         // handled by child
  101.         return TRUE;
  102.     }
  103.  
  104.     if (CFrameWnd::OnCommandHelp(wParam, lParam))
  105.     {
  106.         // handled by our base
  107.         return TRUE;
  108.     }
  109.  
  110.     if (lParam != 0)
  111.     {
  112.         CWinApp* pApp = AfxGetApp();
  113.         if (pApp != NULL)
  114.         {
  115.             AfxGetApp()->WinHelp(lParam);
  116.             return TRUE;
  117.         }
  118.     }
  119.     return FALSE;
  120. }
  121.  
  122. BOOL CMDIFrameWnd::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext*)
  123. {
  124.     CMenu* pMenu = NULL;
  125.     if (m_hMenuDefault == NULL)
  126.     {
  127.         // default implementation for MFC V1 backward compatibility
  128.         pMenu = GetMenu();
  129.         ASSERT(pMenu != NULL);
  130.         // This is attempting to guess which sub-menu is the Window menu.
  131.         // The Windows user interface guidelines say that the right-most
  132.         // menu on the menu bar should be Help and Window should be one
  133.         // to the left of that.
  134.         int iMenu = pMenu->GetMenuItemCount() - 2;
  135.  
  136.         // If this assertion fails, your menu bar does not follow the guidelines
  137.         // so you will have to override this function and call CreateClient
  138.         // appropriately or use the MFC V2 MDI functionality.
  139.         ASSERT(iMenu >= 0);
  140.         pMenu = pMenu->GetSubMenu(iMenu);
  141.         ASSERT(pMenu != NULL);
  142.     }
  143.  
  144.     return CreateClient(lpcs, pMenu);
  145. }
  146.  
  147. BOOL CMDIFrameWnd::CreateClient(LPCREATESTRUCT lpCreateStruct,
  148.     CMenu* pWindowMenu)
  149. {
  150.     ASSERT(m_hWnd != NULL);
  151.     ASSERT(m_hWndMDIClient == NULL);
  152.     DWORD dwStyle = WS_VISIBLE | WS_CHILD | WS_BORDER |
  153.         WS_CLIPCHILDREN | WS_CLIPSIBLINGS |
  154.         MDIS_ALLCHILDSTYLES;    // allow children to be created invisible
  155.     DWORD dwExStyle = 0;
  156.     // will be inset by the frame
  157.  
  158.     if (afxData.bWin4)
  159.     {
  160.         // special styles for 3d effect on Win4
  161.         dwStyle &= ~WS_BORDER;
  162.         dwExStyle = WS_EX_CLIENTEDGE;
  163.     }
  164.  
  165.     CLIENTCREATESTRUCT ccs;
  166.     ccs.hWindowMenu = pWindowMenu->GetSafeHmenu();
  167.         // set hWindowMenu for MFC V1 backward compatibility
  168.         // for MFC V2, window menu will be set in OnMDIActivate
  169.     ccs.idFirstChild = AFX_IDM_FIRST_MDICHILD;
  170.  
  171.     if (lpCreateStruct->style & (WS_HSCROLL|WS_VSCROLL))
  172.     {
  173.         // parent MDIFrame's scroll styles move to the MDICLIENT
  174.         dwStyle |= (lpCreateStruct->style & (WS_HSCROLL|WS_VSCROLL));
  175.  
  176.         // fast way to turn off the scrollbar bits (without a resize)
  177.         ModifyStyle(WS_HSCROLL|WS_VSCROLL, 0, SWP_NOREDRAW|SWP_FRAMECHANGED);
  178.     }
  179.  
  180.     // Create MDICLIENT control with special IDC
  181.     if ((m_hWndMDIClient = ::CreateWindowEx(dwExStyle, _T("mdiclient"), NULL,
  182.         dwStyle, 0, 0, 0, 0, m_hWnd, (HMENU)AFX_IDW_PANE_FIRST,
  183.         AfxGetInstanceHandle(), (LPVOID)&ccs)) == NULL)
  184.     {
  185.         TRACE(_T("Warning: CMDIFrameWnd::OnCreateClient: failed to create MDICLIENT.")
  186.             _T(" GetLastError returns 0x%8.8X\n"), ::GetLastError());
  187.         return FALSE;
  188.     }
  189.     // Move it to the top of z-order
  190.     ::BringWindowToTop(m_hWndMDIClient);
  191.  
  192.     return TRUE;
  193. }
  194.  
  195. LRESULT CMDIFrameWnd::DefWindowProc(UINT nMsg, WPARAM wParam, LPARAM lParam)
  196. {
  197.     return ::DefFrameProc(m_hWnd, m_hWndMDIClient, nMsg, wParam, lParam);
  198. }
  199.  
  200. BOOL CMDIFrameWnd::PreTranslateMessage(MSG* pMsg)
  201. {
  202.     // check for special cancel modes for ComboBoxes
  203.     if (pMsg->message == WM_LBUTTONDOWN || pMsg->message == WM_NCLBUTTONDOWN)
  204.         AfxCancelModes(pMsg->hwnd);    // filter clicks
  205.  
  206.     // allow tooltip messages to be filtered
  207.     if (CWnd::PreTranslateMessage(pMsg))
  208.         return TRUE;
  209.  
  210. #ifndef _AFX_NO_OLE_SUPPORT
  211.     // allow hook to consume message
  212.     if (m_pNotifyHook != NULL && m_pNotifyHook->OnPreTranslateMessage(pMsg))
  213.         return TRUE;
  214. #endif
  215.  
  216.     CMDIChildWnd* pActiveChild = MDIGetActive();
  217.  
  218.     // current active child gets first crack at it
  219.     if (pActiveChild != NULL && pActiveChild->PreTranslateMessage(pMsg))
  220.         return TRUE;
  221.  
  222.     if (pMsg->message >= WM_KEYFIRST && pMsg->message <= WM_KEYLAST)
  223.     {
  224.         // translate accelerators for frame and any children
  225.         if (m_hAccelTable != NULL &&
  226.             ::TranslateAccelerator(m_hWnd, m_hAccelTable, pMsg))
  227.         {
  228.             return TRUE;
  229.         }
  230.  
  231.         // special processing for MDI accelerators last
  232.         // and only if it is not in SDI mode (print preview)
  233.         if (GetActiveView() == NULL)
  234.         {
  235.             if (pMsg->message == WM_KEYDOWN || pMsg->message == WM_SYSKEYDOWN)
  236.             {
  237.                 // the MDICLIENT window may translate it
  238.                 if (::TranslateMDISysAccel(m_hWndMDIClient, pMsg))
  239.                     return TRUE;
  240.             }
  241.         }
  242.     }
  243.  
  244.     return FALSE;
  245. }
  246.  
  247. void CMDIFrameWnd::DelayUpdateFrameMenu(HMENU hMenuAlt)
  248. {
  249.     OnUpdateFrameMenu(hMenuAlt);
  250.  
  251.     m_nIdleFlags |= idleMenu;
  252. }
  253.  
  254. void CMDIFrameWnd::OnIdleUpdateCmdUI()
  255. {
  256.     if (m_nIdleFlags & idleMenu)
  257.     {
  258.         DrawMenuBar();
  259.         m_nIdleFlags &= ~idleMenu;
  260.     }
  261.     CFrameWnd::OnIdleUpdateCmdUI();
  262. }
  263.  
  264. CFrameWnd* CMDIFrameWnd::GetActiveFrame()
  265. {
  266.     CMDIChildWnd* pActiveChild = MDIGetActive();
  267.     if (pActiveChild == NULL)
  268.         return this;
  269.     return pActiveChild;
  270. }
  271.  
  272. BOOL CMDIFrameWnd::PreCreateWindow(CREATESTRUCT& cs)
  273. {
  274.     if (cs.lpszClass == NULL)
  275.     {
  276.         VERIFY(AfxDeferRegisterClass(AFX_WNDMDIFRAME_REG));
  277.         cs.lpszClass = _afxWndMDIFrame;
  278.     }
  279.     return TRUE;
  280. }
  281.  
  282. BOOL CMDIFrameWnd::LoadFrame(UINT nIDResource, DWORD dwDefaultStyle,
  283.     CWnd* pParentWnd, CCreateContext* pContext)
  284. {
  285.     if (!CFrameWnd::LoadFrame(nIDResource, dwDefaultStyle,
  286.       pParentWnd, pContext))
  287.         return FALSE;
  288.  
  289.     // save menu to use when no active MDI child window is present
  290.     ASSERT(m_hWnd != NULL);
  291.     m_hMenuDefault = ::GetMenu(m_hWnd);
  292.     if (m_hMenuDefault == NULL)
  293.         TRACE0("Warning: CMDIFrameWnd without a default menu.\n");
  294.     return TRUE;
  295. }
  296.  
  297. void CMDIFrameWnd::OnDestroy()
  298. {
  299.     CFrameWnd::OnDestroy();     // exit and misc cleanup
  300.  
  301.     // owned menu stored in shared slot for MDIFRAME
  302.     if (m_hMenuDefault != NULL && ::GetMenu(m_hWnd) != m_hMenuDefault)
  303.     {
  304.         // must go through MDI client to get rid of MDI menu additions
  305.         ::SendMessage(m_hWndMDIClient, WM_MDISETMENU,
  306.             (WPARAM)m_hMenuDefault, NULL);
  307.         ASSERT(::GetMenu(m_hWnd) == m_hMenuDefault);
  308.     }
  309. }
  310.  
  311. void CMDIFrameWnd::OnSize(UINT nType, int, int)
  312. {
  313.     // do not call default - it will reposition the MDICLIENT
  314.     if (nType != SIZE_MINIMIZED)
  315.         RecalcLayout();
  316. }
  317.  
  318. LRESULT CMDIFrameWnd::OnMenuChar(UINT nChar, UINT, CMenu*)
  319. {
  320.     // do not call Default() for Alt+(-) when in print preview mode
  321.     if (m_lpfnCloseProc != NULL && nChar == (UINT)'-')
  322.         return 0;
  323.     else
  324.         return Default();
  325. }
  326.  
  327. CMDIChildWnd* CMDIFrameWnd::MDIGetActive(BOOL* pbMaximized) const
  328. {
  329.     // check first for MDI client window not created
  330.     if (m_hWndMDIClient == NULL)
  331.     {
  332.         if (pbMaximized != NULL)
  333.             *pbMaximized = FALSE;
  334.         return NULL;
  335.     }
  336.  
  337.     // MDI client has been created, get active MDI child
  338.     HWND hWnd = (HWND)::SendMessage(m_hWndMDIClient, WM_MDIGETACTIVE, 0,
  339.         (LPARAM)pbMaximized);
  340.     CMDIChildWnd* pWnd = (CMDIChildWnd*)CWnd::FromHandle(hWnd);
  341.     ASSERT(pWnd == NULL || pWnd->IsKindOf(RUNTIME_CLASS(CMDIChildWnd)));
  342.  
  343.     // check for special pseudo-inactive state
  344.     if (pWnd != NULL && pWnd->m_bPseudoInactive &&
  345.         (pWnd->GetStyle() & WS_VISIBLE) == 0)
  346.     {
  347.         // Window is hidden, active, but m_bPseudoInactive -- return NULL
  348.         pWnd = NULL;
  349.         // Ignore maximized flag if pseudo-inactive and maximized
  350.         if (pbMaximized != NULL)
  351.             *pbMaximized = FALSE;
  352.     }
  353.     return pWnd;
  354. }
  355.  
  356.  
  357. CMDIChildWnd* CMDIFrameWnd::CreateNewChild(CRuntimeClass* pClass,
  358.         UINT nResources, HMENU hMenu /* = NULL */, HACCEL hAccel /* = NULL */)
  359. {
  360.     ASSERT(pClass != NULL);
  361.     CMDIChildWnd* pFrame = (CMDIChildWnd*) pClass->CreateObject();
  362.     ASSERT_KINDOF(CMDIChildWnd, pFrame);
  363.  
  364.     // load the frame
  365.     CCreateContext context;
  366.     context.m_pCurrentFrame = this;
  367.  
  368.     if (!pFrame->LoadFrame(nResources,
  369.             WS_OVERLAPPEDWINDOW | FWS_ADDTOTITLE, NULL, &context))
  370.     {
  371.         TRACE0("Couldn't load frame window.\n");
  372.         delete pFrame;
  373.         return NULL;
  374.     }
  375.  
  376.     CString strFullString, strTitle;
  377.     if (strFullString.LoadString(nResources))
  378.         AfxExtractSubString(strTitle, strFullString, CDocTemplate::docName);
  379.  
  380.     // set the handles and redraw the frame and parent
  381.     pFrame->SetHandles(hMenu, hAccel);
  382.     pFrame->SetTitle(strTitle);
  383.     pFrame->InitialUpdateFrame(NULL, TRUE);
  384.  
  385.     return pFrame;
  386. }
  387.  
  388. /////////////////////////////////////////////////////////////////////////////
  389. // CMDIFrameWnd Diagnostics
  390.  
  391. #ifdef _DEBUG
  392. void CMDIFrameWnd::AssertValid() const
  393. {
  394.     CFrameWnd::AssertValid();
  395.     ASSERT(m_hWndMDIClient == NULL || ::IsWindow(m_hWndMDIClient));
  396.     ASSERT(m_hMenuDefault == NULL || ::IsMenu(m_hMenuDefault));
  397. }
  398.  
  399. void CMDIFrameWnd::Dump(CDumpContext& dc) const
  400. {
  401.     CFrameWnd::Dump(dc);
  402.  
  403.     dc << "m_hWndMDIClient = " << (UINT)m_hWndMDIClient;
  404.     dc << "\nm_hMenuDefault = " << (UINT)m_hMenuDefault;
  405.  
  406.     dc << "\n";
  407. }
  408. #endif //_DEBUG
  409.  
  410. /////////////////////////////////////////////////////////////////////////////
  411. // CMDIChildWnd
  412.  
  413. BEGIN_MESSAGE_MAP(CMDIChildWnd, CFrameWnd)
  414.     //{{AFX_MSG_MAP(CMDIChildWnd)
  415.     ON_WM_MOUSEACTIVATE()
  416.     ON_WM_NCACTIVATE()
  417.     ON_WM_MDIACTIVATE()
  418.     ON_WM_SIZE()
  419.     ON_WM_WINDOWPOSCHANGING()
  420.     ON_WM_NCCREATE()
  421.     ON_WM_CREATE()
  422.     ON_WM_DESTROY()
  423.     ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTW, 0, 0xFFFF, OnToolTipText)
  424.     ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTA, 0, 0xFFFF, OnToolTipText)
  425.     //}}AFX_MSG_MAP
  426. END_MESSAGE_MAP()
  427.  
  428. CMDIChildWnd::CMDIChildWnd()
  429. {
  430.     m_hMenuShared = NULL;
  431.     m_bPseudoInactive = FALSE;
  432. }
  433.  
  434. /////////////////////////////////////////////////////////////////////////////
  435. // CMDIChildWnd special processing
  436.  
  437. LRESULT CMDIChildWnd::DefWindowProc(UINT nMsg, WPARAM wParam, LPARAM lParam)
  438. {
  439.     return ::DefMDIChildProc(m_hWnd, nMsg, wParam, lParam);
  440. }
  441.  
  442. BOOL CMDIChildWnd::DestroyWindow()
  443. {
  444.     if (m_hWnd == NULL)
  445.         return FALSE;
  446.  
  447.     // avoid changing the caption during the destroy message(s)
  448.     CMDIFrameWnd* pFrameWnd = GetMDIFrame();
  449.     HWND hWndFrame = pFrameWnd->m_hWnd;
  450.     ASSERT(::IsWindow(hWndFrame));
  451.     DWORD dwStyle = SetWindowLong(hWndFrame, GWL_STYLE,
  452.         GetWindowLong(hWndFrame, GWL_STYLE) & ~FWS_ADDTOTITLE);
  453.  
  454.     MDIDestroy();
  455.  
  456.     if (::IsWindow(hWndFrame))
  457.     {
  458.         ASSERT(hWndFrame == pFrameWnd->m_hWnd);
  459.         SetWindowLong(hWndFrame, GWL_STYLE, dwStyle);
  460.         pFrameWnd->OnUpdateFrameTitle(TRUE);
  461.     }
  462.  
  463.     return TRUE;
  464. }
  465.  
  466. BOOL CMDIChildWnd::PreTranslateMessage(MSG* pMsg)
  467. {
  468.     // check for special cancel modes for combo boxes
  469.     if (pMsg->message == WM_LBUTTONDOWN || pMsg->message == WM_NCLBUTTONDOWN)
  470.         AfxCancelModes(pMsg->hwnd);    // filter clicks
  471.  
  472.     // allow tooltip messages to be filtered
  473.     if (CWnd::PreTranslateMessage(pMsg))
  474.         return TRUE;
  475.  
  476.     // we can't call 'CFrameWnd::PreTranslate' since it will translate
  477.     //  accelerators in the context of the MDI Child - but since MDI Child
  478.     //  windows don't have menus this doesn't work properly.  MDI Child
  479.     //  accelerators must be translated in context of their MDI Frame.
  480.  
  481.     if (pMsg->message >= WM_KEYFIRST && pMsg->message <= WM_KEYLAST)
  482.     {
  483.         // use document specific accelerator table over m_hAccelTable
  484.         HACCEL hAccel = GetDefaultAccelerator();
  485.         return hAccel != NULL &&
  486.            ::TranslateAccelerator(GetMDIFrame()->m_hWnd, hAccel, pMsg);
  487.     }
  488.     return FALSE;
  489. }
  490.  
  491. BOOL CMDIChildWnd::PreCreateWindow(CREATESTRUCT& cs)
  492. {
  493.     ASSERT(cs.style & WS_CHILD);
  494.         // MFC V2 requires that MDI Children are created with proper styles,
  495.         //  usually: WS_CHILD | WS_VISIBLE | WS_OVERLAPPEDWINDOW.
  496.         // See Technical note TN019 for more details on MFC V1->V2 migration.
  497.  
  498.     return CFrameWnd::PreCreateWindow(cs);
  499. }
  500.  
  501. BOOL CMDIChildWnd::Create(LPCTSTR lpszClassName,
  502.     LPCTSTR lpszWindowName, DWORD dwStyle,
  503.     const RECT& rect, CMDIFrameWnd* pParentWnd,
  504.     CCreateContext* pContext)
  505. {
  506.     if (pParentWnd == NULL)
  507.     {
  508.         CWnd* pMainWnd = AfxGetThread()->m_pMainWnd;
  509.         ASSERT(pMainWnd != NULL);
  510.         ASSERT_KINDOF(CMDIFrameWnd, pMainWnd);
  511.         pParentWnd = (CMDIFrameWnd*)pMainWnd;
  512.     }
  513.     ASSERT(::IsWindow(pParentWnd->m_hWndMDIClient));
  514.  
  515.     // insure correct window positioning
  516.     pParentWnd->RecalcLayout();
  517.  
  518.     // first copy into a CREATESTRUCT for PreCreate
  519.     CREATESTRUCT cs;
  520.     cs.dwExStyle = 0L;
  521.     cs.lpszClass = lpszClassName;
  522.     cs.lpszName = lpszWindowName;
  523.     cs.style = dwStyle;
  524.     cs.x = rect.left;
  525.     cs.y = rect.top;
  526.     cs.cx = rect.right - rect.left;
  527.     cs.cy = rect.bottom - rect.top;
  528.     cs.hwndParent = pParentWnd->m_hWnd;
  529.     cs.hMenu = NULL;
  530.     cs.hInstance = AfxGetInstanceHandle();
  531.     cs.lpCreateParams = (LPVOID)pContext;
  532.  
  533.     if (!PreCreateWindow(cs))
  534.     {
  535.         PostNcDestroy();
  536.         return FALSE;
  537.     }
  538.     // extended style must be zero for MDI Children (except under Win4)
  539.     ASSERT(afxData.bWin4 || cs.dwExStyle == 0);
  540.     ASSERT(cs.hwndParent == pParentWnd->m_hWnd);    // must not change
  541.  
  542.     // now copy into a MDICREATESTRUCT for real create
  543.     MDICREATESTRUCT mcs;
  544.     mcs.szClass = cs.lpszClass;
  545.     mcs.szTitle = cs.lpszName;
  546.     mcs.hOwner = cs.hInstance;
  547.     mcs.x = cs.x;
  548.     mcs.y = cs.y;
  549.     mcs.cx = cs.cx;
  550.     mcs.cy = cs.cy;
  551.     mcs.style = cs.style & ~(WS_MAXIMIZE | WS_VISIBLE);
  552.     mcs.lParam = (LONG)cs.lpCreateParams;
  553.  
  554.     // create the window through the MDICLIENT window
  555.     AfxHookWindowCreate(this);
  556.     HWND hWnd = (HWND)::SendMessage(pParentWnd->m_hWndMDIClient,
  557.         WM_MDICREATE, 0, (LPARAM)&mcs);
  558.     if (!AfxUnhookWindowCreate())
  559.         PostNcDestroy();        // cleanup if MDICREATE fails too soon
  560.  
  561.     if (hWnd == NULL)
  562.         return FALSE;
  563.  
  564.     // special handling of visibility (always created invisible)
  565.     if (cs.style & WS_VISIBLE)
  566.     {
  567.         // place the window on top in z-order before showing it
  568.         ::BringWindowToTop(hWnd);
  569.  
  570.         // show it as specified
  571.         if (cs.style & WS_MINIMIZE)
  572.             ShowWindow(SW_SHOWMINIMIZED);
  573.         else if (cs.style & WS_MAXIMIZE)
  574.             ShowWindow(SW_SHOWMAXIMIZED);
  575.         else
  576.             ShowWindow(SW_SHOWNORMAL);
  577.  
  578.         // make sure it is active (visibility == activation)
  579.         pParentWnd->MDIActivate(this);
  580.  
  581.         // refresh MDI Window menu
  582.         ::SendMessage(pParentWnd->m_hWndMDIClient, WM_MDIREFRESHMENU, 0, 0);
  583.     }
  584.  
  585.     ASSERT(hWnd == m_hWnd);
  586.     return TRUE;
  587. }
  588.  
  589. BOOL CMDIChildWnd::LoadFrame(UINT nIDResource, DWORD dwDefaultStyle,
  590.         CWnd* pParentWnd, CCreateContext* pContext)
  591. {
  592.     // only do this once
  593.     ASSERT_VALID_IDR(nIDResource);
  594.     ASSERT(m_nIDHelp == 0 || m_nIDHelp == nIDResource);
  595.     ASSERT(m_hMenuShared == NULL);      // only do once
  596.  
  597.     m_nIDHelp = nIDResource;    // ID for help context (+HID_BASE_RESOURCE)
  598.  
  599.     // parent must be MDI Frame (or NULL for default)
  600.     ASSERT(pParentWnd == NULL || pParentWnd->IsKindOf(RUNTIME_CLASS(CMDIFrameWnd)));
  601.     // will be a child of MDIClient
  602.     ASSERT(!(dwDefaultStyle & WS_POPUP));
  603.     dwDefaultStyle |= WS_CHILD;
  604.  
  605.     // if available - get MDI child menus from doc template
  606.     ASSERT(m_hMenuShared == NULL);      // only do once
  607.     CMultiDocTemplate* pTemplate;
  608.     if (pContext != NULL &&
  609.         (pTemplate = (CMultiDocTemplate*)pContext->m_pNewDocTemplate) != NULL)
  610.     {
  611.         ASSERT_KINDOF(CMultiDocTemplate, pTemplate);
  612.         // get shared menu from doc template
  613.         m_hMenuShared = pTemplate->m_hMenuShared;
  614.         m_hAccelTable = pTemplate->m_hAccelTable;
  615.     }
  616.     else
  617.     {
  618.         TRACE0("Warning: no shared menu/acceltable for MDI Child window.\n");
  619.             // if this happens, programmer must load these manually
  620.     }
  621.  
  622.     CString strFullString, strTitle;
  623.     if (strFullString.LoadString(nIDResource))
  624.         AfxExtractSubString(strTitle, strFullString, 0);    // first sub-string
  625.  
  626.     ASSERT(m_hWnd == NULL);
  627.     if (!Create(GetIconWndClass(dwDefaultStyle, nIDResource),
  628.       strTitle, dwDefaultStyle, rectDefault,
  629.       (CMDIFrameWnd*)pParentWnd, pContext))
  630.     {
  631.         return FALSE;   // will self destruct on failure normally
  632.     }
  633.  
  634.     // it worked !
  635.     return TRUE;
  636. }
  637.  
  638. void CMDIChildWnd::OnSize(UINT nType, int cx, int cy)
  639. {
  640.     CFrameWnd::OnSize(nType, cx, cy);
  641.  
  642.     // update our parent frame - in case we are now maximized or not
  643.     GetMDIFrame()->OnUpdateFrameTitle(TRUE);
  644. }
  645.  
  646. BOOL CMDIChildWnd::UpdateClientEdge(LPRECT lpRect)
  647. {
  648.     if (!afxData.bWin4)
  649.         return FALSE;
  650.  
  651.     // only adjust for active MDI child window
  652.     CMDIFrameWnd* pFrameWnd = GetMDIFrame();
  653.     CMDIChildWnd* pChild = pFrameWnd->MDIGetActive();
  654.     if (pChild == NULL || pChild == this)
  655.     {
  656.         // need to adjust the client edge style as max/restore happens
  657.         DWORD dwStyle = ::GetWindowLong(pFrameWnd->m_hWndMDIClient, GWL_EXSTYLE);
  658.         DWORD dwNewStyle = dwStyle;
  659.         if (pChild != NULL && !(GetExStyle() & WS_EX_CLIENTEDGE) &&
  660.           (GetStyle() & WS_MAXIMIZE))
  661.             dwNewStyle &= ~(WS_EX_CLIENTEDGE);
  662.         else
  663.             dwNewStyle |= WS_EX_CLIENTEDGE;
  664.  
  665.         if (dwStyle != dwNewStyle)
  666.         {
  667.             // SetWindowPos will not move invalid bits
  668.             ::RedrawWindow(pFrameWnd->m_hWndMDIClient, NULL, NULL,
  669.                 RDW_INVALIDATE | RDW_ALLCHILDREN);
  670.  
  671.             // remove/add WS_EX_CLIENTEDGE to MDI client area
  672.             ::SetWindowLong(pFrameWnd->m_hWndMDIClient, GWL_EXSTYLE, dwNewStyle);
  673.             ::SetWindowPos(pFrameWnd->m_hWndMDIClient, NULL, 0, 0, 0, 0,
  674.                 SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE |
  675.                 SWP_NOZORDER | SWP_NOCOPYBITS);
  676.  
  677.             // return new client area
  678.             if (lpRect != NULL)
  679.                 ::GetClientRect(pFrameWnd->m_hWndMDIClient, lpRect);
  680.             return TRUE;
  681.         }
  682.     }
  683.     return FALSE;
  684. }
  685.  
  686. void CMDIChildWnd::OnWindowPosChanging(LPWINDOWPOS lpWndPos)
  687. {
  688.     if (afxData.bWin4 && !(lpWndPos->flags & SWP_NOSIZE))
  689.     {
  690.         CRect rectClient;
  691.         if (UpdateClientEdge(rectClient) && (GetStyle() & WS_MAXIMIZE))
  692.         {
  693.             // adjust maximized window size and position based on new
  694.             //  size/position of the MDI client area.
  695.             ::AdjustWindowRectEx(rectClient, GetStyle(), FALSE, GetExStyle());
  696.             lpWndPos->x = rectClient.left;
  697.             lpWndPos->y = rectClient.top;
  698.             lpWndPos->cx = rectClient.Width();
  699.             lpWndPos->cy = rectClient.Height();
  700.         }
  701.     }
  702.  
  703.     CFrameWnd::OnWindowPosChanging(lpWndPos);
  704. }
  705.  
  706. void CMDIChildWnd::OnDestroy()
  707. {
  708.     UpdateClientEdge();
  709.  
  710.     CFrameWnd::OnDestroy();
  711. }
  712.  
  713. BOOL CMDIChildWnd::OnNcActivate(BOOL bActive)
  714. {
  715.     // bypass CFrameWnd::OnNcActivate()
  716.     return CWnd::OnNcActivate(bActive);
  717. }
  718.  
  719. int CMDIChildWnd::OnMouseActivate(CWnd* pDesktopWnd, UINT nHitTest, UINT message)
  720. {
  721.     int nResult = CFrameWnd::OnMouseActivate(pDesktopWnd, nHitTest, message);
  722.     if (nResult == MA_NOACTIVATE || nResult == MA_NOACTIVATEANDEAT)
  723.         return nResult;   // frame does not want to activate
  724.  
  725.     // activate this window if necessary
  726.     CMDIFrameWnd* pFrameWnd = GetMDIFrame();
  727.     ASSERT_VALID(pFrameWnd);
  728.     CMDIChildWnd* pActive = pFrameWnd->MDIGetActive();
  729.     if (pActive != this)
  730.         MDIActivate();
  731.  
  732.     return nResult;
  733. }
  734.  
  735. BOOL CMDIChildWnd::OnToolTipText(UINT msg, NMHDR* pNMHDR, LRESULT* pResult)
  736. {
  737.     ASSERT(pNMHDR->code == TTN_NEEDTEXTA || pNMHDR->code == TTN_NEEDTEXTW);
  738.     UNUSED(pNMHDR);
  739.  
  740.     // check to see if the message is going directly to this window or not
  741.     const MSG* pMsg = GetCurrentMessage();
  742.     if (pMsg->hwnd != m_hWnd)
  743.     {
  744.         // let top level frame handle this for us
  745.         return FALSE;
  746.     }
  747.  
  748.     // otherwise, handle it ourselves
  749.     return CFrameWnd::OnToolTipText(msg, pNMHDR, pResult);
  750. }
  751.  
  752. void CMDIChildWnd::ActivateFrame(int nCmdShow)
  753. {
  754.     BOOL bVisibleThen = (GetStyle() & WS_VISIBLE) != 0;
  755.     CMDIFrameWnd* pFrameWnd = GetMDIFrame();
  756.     ASSERT_VALID(pFrameWnd);
  757.  
  758.     // determine default show command
  759.     if (nCmdShow == -1)
  760.     {
  761.         // get maximized state of frame window (previously active child)
  762.         BOOL bMaximized;
  763.         pFrameWnd->MDIGetActive(&bMaximized);
  764.  
  765.         // convert show command based on current style
  766.         DWORD dwStyle = GetStyle();
  767.         if (bMaximized || (dwStyle & WS_MAXIMIZE))
  768.             nCmdShow = SW_SHOWMAXIMIZED;
  769.         else if (dwStyle & WS_MINIMIZE)
  770.             nCmdShow = SW_SHOWMINIMIZED;
  771.     }
  772.  
  773.     // finally, show the window
  774.     CFrameWnd::ActivateFrame(nCmdShow);
  775.  
  776.     // update the Window menu to reflect new child window
  777.     CMDIFrameWnd* pFrame = GetMDIFrame();
  778.     ::SendMessage(pFrame->m_hWndMDIClient, WM_MDIREFRESHMENU, 0, 0);
  779.  
  780.     // Note: Update the m_bPseudoInactive flag.  This is used to handle the
  781.     //  last MDI child getting hidden.  Windows provides no way to deactivate
  782.     //  an MDI child window.
  783.  
  784.     BOOL bVisibleNow = (GetStyle() & WS_VISIBLE) != 0;
  785.     if (bVisibleNow == bVisibleThen)
  786.         return;
  787.  
  788.     if (!bVisibleNow)
  789.     {
  790.         // get current active window according to Windows MDI
  791.         HWND hWnd = (HWND)::SendMessage(pFrameWnd->m_hWndMDIClient,
  792.             WM_MDIGETACTIVE, 0, 0);
  793.         if (hWnd != m_hWnd)
  794.         {
  795.             // not active any more -- window must have been deactivated
  796.             ASSERT(!m_bPseudoInactive);
  797.             return;
  798.         }
  799.  
  800.         // check next window
  801.         ASSERT(hWnd != NULL);
  802.         pFrameWnd->MDINext();
  803.  
  804.         // see if it has been deactivated now...
  805.         hWnd = (HWND)::SendMessage(pFrameWnd->m_hWndMDIClient,
  806.             WM_MDIGETACTIVE, 0, 0);
  807.         if (hWnd == m_hWnd)
  808.         {
  809.             // still active -- fake deactivate it
  810.             ASSERT(hWnd != NULL);
  811.             OnMDIActivate(FALSE, NULL, this);
  812.             m_bPseudoInactive = TRUE;   // so MDIGetActive returns NULL
  813.         }
  814.     }
  815.     else if (m_bPseudoInactive)
  816.     {
  817.         // if state transitioned from not visible to visible, but
  818.         //  was pseudo deactivated -- send activate notify now
  819.         OnMDIActivate(TRUE, this, NULL);
  820.         ASSERT(!m_bPseudoInactive); // should get set in OnMDIActivate!
  821.     }
  822. }
  823.  
  824. void CMDIChildWnd::SetHandles(HMENU hMenu, HACCEL hAccel)
  825. {
  826.     m_hMenuShared = hMenu;
  827.     m_hAccelTable = hAccel;
  828. }
  829.  
  830. /////////////////////////////////////////////////////////////////////////////
  831. // CMDIChildWnd Diagnostics
  832.  
  833. #ifdef _DEBUG
  834. void CMDIChildWnd::AssertValid() const
  835. {
  836.     CFrameWnd::AssertValid();
  837.     ASSERT(m_hMenuShared == NULL || ::IsMenu(m_hMenuShared));
  838. }
  839.  
  840. void CMDIChildWnd::Dump(CDumpContext& dc) const
  841. {
  842.     CFrameWnd::Dump(dc);
  843.  
  844.     dc << "m_hMenuShared = " << (UINT)m_hMenuShared;
  845.     dc << "\n";
  846. }
  847. #endif //_DEBUG
  848.  
  849. /////////////////////////////////////////////////////////////////////////////
  850. // Smarts for the "Window" menu
  851.  
  852. HMENU CMDIFrameWnd::GetWindowMenuPopup(HMENU hMenuBar)
  853.     // find which popup is the "Window" menu
  854. {
  855.     if (hMenuBar == NULL)
  856.         return NULL;
  857.  
  858.     ASSERT(::IsMenu(hMenuBar));
  859.  
  860.     int iItem = ::GetMenuItemCount(hMenuBar);
  861.     while (iItem--)
  862.     {
  863.         HMENU hMenuPop = ::GetSubMenu(hMenuBar, iItem);
  864.         if (hMenuPop != NULL)
  865.         {
  866.             int iItemMax = ::GetMenuItemCount(hMenuPop);
  867.             for (int iItemPop = 0; iItemPop < iItemMax; iItemPop++)
  868.             {
  869.                 UINT nID = GetMenuItemID(hMenuPop, iItemPop);
  870.                 if (nID >= AFX_IDM_WINDOW_FIRST && nID <= AFX_IDM_WINDOW_LAST)
  871.                     return hMenuPop;
  872.             }
  873.         }
  874.     }
  875.  
  876.     // no default menu found
  877.     TRACE0("Warning: GetWindowMenuPopup failed!\n");
  878.     return NULL;
  879. }
  880.  
  881. /////////////////////////////////////////////////////////////////////////////
  882. // Smarts for updating the window menu based on the current child
  883.  
  884. void CMDIFrameWnd::OnUpdateFrameMenu(HMENU hMenuAlt)
  885. {
  886.     CMDIChildWnd* pActiveWnd = MDIGetActive();
  887.     if (pActiveWnd != NULL)
  888.     {
  889.         // let child update the menu bar
  890.         pActiveWnd->OnUpdateFrameMenu(TRUE, pActiveWnd, hMenuAlt);
  891.     }
  892.     else
  893.     {
  894.         // no child active, so have to update it ourselves
  895.         //  (we can't send it to a child window, since pActiveWnd is NULL)
  896.         if (hMenuAlt == NULL)
  897.             hMenuAlt = m_hMenuDefault;  // use default
  898.         ::SendMessage(m_hWndMDIClient, WM_MDISETMENU, (WPARAM)hMenuAlt, NULL);
  899.     }
  900. }
  901.  
  902. /////////////////////////////////////////////////////////////////////////////
  903. // MDI Child Extensions
  904.  
  905. // walk up two parents for MDIFrame that owns MDIChild (skip MDIClient)
  906. CMDIFrameWnd* CMDIChildWnd::GetMDIFrame()
  907. {
  908.     ASSERT_KINDOF(CMDIChildWnd, this);
  909.     ASSERT(m_hWnd != NULL);
  910.     HWND hWndMDIClient = ::GetParent(m_hWnd);
  911.     ASSERT(hWndMDIClient != NULL);
  912.  
  913.     CMDIFrameWnd* pMDIFrame;
  914.     pMDIFrame = (CMDIFrameWnd*)CWnd::FromHandle(::GetParent(hWndMDIClient));
  915.     ASSERT(pMDIFrame != NULL);
  916.     ASSERT_KINDOF(CMDIFrameWnd, pMDIFrame);
  917.     ASSERT(pMDIFrame->m_hWndMDIClient == hWndMDIClient);
  918.     ASSERT_VALID(pMDIFrame);
  919.     return pMDIFrame;
  920. }
  921.  
  922. CWnd* CMDIChildWnd::GetMessageBar()
  923. {
  924.     // status bar/message bar owned by parent MDI frame
  925.     return GetMDIFrame()->GetMessageBar();
  926. }
  927.  
  928. void CMDIChildWnd::OnUpdateFrameTitle(BOOL bAddToTitle)
  929. {
  930.     // update our parent window first
  931.     GetMDIFrame()->OnUpdateFrameTitle(bAddToTitle);
  932.  
  933.     if ((GetStyle() & FWS_ADDTOTITLE) == 0)
  934.         return;     // leave child window alone!
  935.  
  936.     CDocument* pDocument = GetActiveDocument();
  937.     if (bAddToTitle)
  938.     {
  939.         TCHAR szText[256+_MAX_PATH];
  940.         if (pDocument == NULL)
  941.             lstrcpy(szText, m_strTitle);
  942.         else
  943.             lstrcpy(szText, pDocument->GetTitle());
  944.         if (m_nWindow > 0)
  945.             wsprintf(szText + lstrlen(szText), _T(":%d"), m_nWindow);
  946.  
  947.         // set title if changed, but don't remove completely
  948.         AfxSetWindowText(m_hWnd, szText);
  949.     }
  950. }
  951.  
  952. void CMDIChildWnd::OnMDIActivate(BOOL bActivate, CWnd* pActivateWnd, CWnd*)
  953. {
  954.     m_bPseudoInactive = FALSE;  // must be happening for real
  955.  
  956.     // make sure MDI client window has correct client edge
  957.     UpdateClientEdge();
  958.  
  959.     // send deactivate notification to active view
  960.     CView* pActiveView = GetActiveView();
  961.     if (!bActivate && pActiveView != NULL)
  962.         pActiveView->OnActivateView(FALSE, pActiveView, pActiveView);
  963.  
  964.     // allow hook to short circuit normal activation
  965.     BOOL bHooked = FALSE;
  966. #ifndef _AFX_NO_OLE_SUPPORT
  967.     if (m_pNotifyHook != NULL && m_pNotifyHook->OnDocActivate(bActivate))
  968.         bHooked = TRUE;
  969. #endif
  970.  
  971.     // update titles (don't AddToTitle if deactivate last)
  972.     if (!bHooked)
  973.         OnUpdateFrameTitle(bActivate || (pActivateWnd != NULL));
  974.  
  975.     // re-activate the appropriate view
  976.     if (bActivate)
  977.     {
  978.         if (pActiveView != NULL && GetMDIFrame() == GetActiveWindow())
  979.             pActiveView->OnActivateView(TRUE, pActiveView, pActiveView);
  980.     }
  981.  
  982.     // update menus
  983.     if (!bHooked)
  984.     {
  985.         OnUpdateFrameMenu(bActivate, pActivateWnd, NULL);
  986.         GetMDIFrame()->DrawMenuBar();
  987.     }
  988. }
  989.  
  990. void CMDIChildWnd::OnUpdateFrameMenu(BOOL bActivate, CWnd* pActivateWnd,
  991.     HMENU hMenuAlt)
  992. {
  993.     CMDIFrameWnd* pFrame = GetMDIFrame();
  994.  
  995.     if (hMenuAlt == NULL && bActivate)
  996.     {
  997.         // attempt to get default menu from document
  998.         CDocument* pDoc = GetActiveDocument();
  999.         if (pDoc != NULL)
  1000.             hMenuAlt = pDoc->GetDefaultMenu();
  1001.     }
  1002.  
  1003.     // use default menu stored in frame if none from document
  1004.     if (hMenuAlt == NULL)
  1005.         hMenuAlt = m_hMenuShared;
  1006.  
  1007.     if (hMenuAlt != NULL && bActivate)
  1008.     {
  1009.         ASSERT(pActivateWnd == this);
  1010.  
  1011.         // activating child, set parent menu
  1012.         ::SendMessage(pFrame->m_hWndMDIClient, WM_MDISETMENU,
  1013.             (WPARAM)hMenuAlt, (LPARAM)pFrame->GetWindowMenuPopup(hMenuAlt));
  1014.     }
  1015.     else if (hMenuAlt != NULL && !bActivate && pActivateWnd == NULL)
  1016.     {
  1017.         // destroying last child
  1018.         HMENU hMenuLast = NULL;
  1019.         ::SendMessage(pFrame->m_hWndMDIClient, WM_MDISETMENU,
  1020.             (WPARAM)pFrame->m_hMenuDefault, (LPARAM)hMenuLast);
  1021.     }
  1022.     else
  1023.     {
  1024.         // refresh MDI Window menu (even if non-shared menu)
  1025.         ::SendMessage(pFrame->m_hWndMDIClient, WM_MDIREFRESHMENU, 0, 0);
  1026.     }
  1027. }
  1028.  
  1029. BOOL CMDIChildWnd::OnNcCreate(LPCREATESTRUCT lpCreateStruct)
  1030. {
  1031.     if (!CFrameWnd::OnNcCreate(lpCreateStruct))
  1032.         return FALSE;
  1033.  
  1034.     // handle extended styles under Win4
  1035.     // call PreCreateWindow again just to get dwExStyle
  1036.     VERIFY(PreCreateWindow(*lpCreateStruct));
  1037.     SetWindowLong(m_hWnd, GWL_EXSTYLE, lpCreateStruct->dwExStyle);
  1038.  
  1039.     return TRUE;
  1040. }
  1041.  
  1042. int CMDIChildWnd::OnCreate(LPCREATESTRUCT lpCreateStruct)
  1043. {
  1044.     // call base class with lParam context (not MDI one)
  1045.     MDICREATESTRUCT* lpmcs;
  1046.     lpmcs = (MDICREATESTRUCT*)lpCreateStruct->lpCreateParams;
  1047.     CCreateContext* pContext = (CCreateContext*)lpmcs->lParam;
  1048.  
  1049.     return OnCreateHelper(lpCreateStruct, pContext);
  1050. }
  1051.  
  1052. /////////////////////////////////////////////////////////////////////////////
  1053. // Special UI processing depending on current active child
  1054.  
  1055. void CMDIFrameWnd::OnUpdateFrameTitle(BOOL bAddToTitle)
  1056. {
  1057.     if ((GetStyle() & FWS_ADDTOTITLE) == 0)
  1058.         return;     // leave it alone!
  1059.  
  1060. #ifndef _AFX_NO_OLE_SUPPORT
  1061.     // allow hook to set the title (used for OLE support)
  1062.     if (m_pNotifyHook != NULL && m_pNotifyHook->OnUpdateFrameTitle())
  1063.         return;
  1064. #endif
  1065.  
  1066.     CMDIChildWnd* pActiveChild = NULL;
  1067.     CDocument* pDocument = GetActiveDocument();
  1068.     if (bAddToTitle &&
  1069.       (pActiveChild = MDIGetActive()) != NULL &&
  1070.       (pActiveChild->GetStyle() & WS_MAXIMIZE) == 0 &&
  1071.       (pDocument != NULL ||
  1072.        (pDocument = pActiveChild->GetActiveDocument()) != NULL))
  1073.         UpdateFrameTitleForDocument(pDocument->GetTitle());
  1074.     else
  1075.     {
  1076.         LPCTSTR lpstrTitle = NULL;
  1077.         CString strTitle;
  1078.  
  1079.         if (pActiveChild != NULL)
  1080.         {
  1081.             strTitle = pActiveChild->GetTitle();
  1082.             if (!strTitle.IsEmpty())
  1083.                 lpstrTitle = strTitle;
  1084.         }
  1085.         UpdateFrameTitleForDocument(lpstrTitle);
  1086.     }
  1087. }
  1088.  
  1089. /////////////////////////////////////////////////////////////////////////////
  1090. // Standard MDI Commands
  1091.  
  1092. // Two function for all standard MDI "Window" commands
  1093. void CMDIFrameWnd::OnUpdateMDIWindowCmd(CCmdUI* pCmdUI)
  1094. {
  1095.     ASSERT(m_hWndMDIClient != NULL);
  1096.     pCmdUI->Enable(MDIGetActive() != NULL);
  1097. }
  1098.  
  1099. BOOL CMDIFrameWnd::OnMDIWindowCmd(UINT nID)
  1100. {
  1101.     ASSERT(m_hWndMDIClient != NULL);
  1102.  
  1103.     UINT msg;
  1104.     UINT wParam = 0;
  1105.     switch (nID)
  1106.     {
  1107.     default:
  1108.         return FALSE;       // not for us
  1109.     case ID_WINDOW_ARRANGE:
  1110.         msg = WM_MDIICONARRANGE;
  1111.         break;
  1112.     case ID_WINDOW_CASCADE:
  1113.         msg = WM_MDICASCADE;
  1114.         break;
  1115.     case ID_WINDOW_TILE_HORZ:
  1116.         wParam = MDITILE_HORIZONTAL;
  1117.         // fall through
  1118.     case ID_WINDOW_TILE_VERT:
  1119.         ASSERT(MDITILE_VERTICAL == 0);
  1120.         msg = WM_MDITILE;
  1121.         break;
  1122.     }
  1123.  
  1124.     ::SendMessage(m_hWndMDIClient, msg, wParam, 0);
  1125.     return TRUE;
  1126. }
  1127.  
  1128. void CMDIFrameWnd::OnWindowNew()
  1129. {
  1130.     CMDIChildWnd* pActiveChild = MDIGetActive();
  1131.     CDocument* pDocument;
  1132.     if (pActiveChild == NULL ||
  1133.       (pDocument = pActiveChild->GetActiveDocument()) == NULL)
  1134.     {
  1135.         TRACE0("Warning: No active document for WindowNew command.\n");
  1136.         AfxMessageBox(AFX_IDP_COMMAND_FAILURE);
  1137.         return;     // command failed
  1138.     }
  1139.  
  1140.     // otherwise we have a new frame !
  1141.     CDocTemplate* pTemplate = pDocument->GetDocTemplate();
  1142.     ASSERT_VALID(pTemplate);
  1143.     CFrameWnd* pFrame = pTemplate->CreateNewFrame(pDocument, pActiveChild);
  1144.     if (pFrame == NULL)
  1145.     {
  1146.         TRACE0("Warning: failed to create new frame.\n");
  1147.         return;     // command failed
  1148.     }
  1149.  
  1150.     pTemplate->InitialUpdateFrame(pFrame, pDocument);
  1151. }
  1152.  
  1153. #ifdef AFX_INIT_SEG
  1154. #pragma code_seg(AFX_INIT_SEG)
  1155. #endif
  1156.  
  1157. IMPLEMENT_DYNCREATE(CMDIFrameWnd, CFrameWnd)
  1158. IMPLEMENT_DYNCREATE(CMDIChildWnd, CFrameWnd)
  1159.  
  1160. ////////////////////////////////////////////////////////////////////////////
  1161.