home *** CD-ROM | disk | FTP | other *** search
/ Supercompiler 1997 / SUPERCOMPILER97.iso / MS_VC.50 / VC / MFC / SRC / WINMDI.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1996-11-01  |  31.1 KB  |  1,113 lines

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