1 // This is a part of the Microsoft Foundation Classes C++ library.
2 // Copyright (C) Microsoft Corporation
3 // All rights reserved.
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.
12 //#include "afxmdichildwndex.h"
13 //#include "afxmdiframewndex.h"
15 /////////////////////////////////////////////////////////////////////////////
18 BEGIN_MESSAGE_MAP(CMDIFrameWnd
, CFrameWnd
)
19 ON_MESSAGE_VOID(WM_IDLEUPDATECMDUI
, CMDIFrameWnd::OnIdleUpdateCmdUI
)
20 ON_UPDATE_COMMAND_UI(ID_WINDOW_ARRANGE
, &CMDIFrameWnd::OnUpdateMDIWindowCmd
)
21 ON_UPDATE_COMMAND_UI(ID_WINDOW_CASCADE
, &CMDIFrameWnd::OnUpdateMDIWindowCmd
)
22 ON_UPDATE_COMMAND_UI(ID_WINDOW_TILE_HORZ
, &CMDIFrameWnd::OnUpdateMDIWindowCmd
)
23 ON_UPDATE_COMMAND_UI(ID_WINDOW_TILE_VERT
, &CMDIFrameWnd::OnUpdateMDIWindowCmd
)
25 ON_COMMAND_EX(ID_WINDOW_ARRANGE
, &CMDIFrameWnd::OnMDIWindowCmd
)
26 ON_COMMAND_EX(ID_WINDOW_CASCADE
, &CMDIFrameWnd::OnMDIWindowCmd
)
27 ON_COMMAND_EX(ID_WINDOW_TILE_HORZ
, &CMDIFrameWnd::OnMDIWindowCmd
)
28 ON_COMMAND_EX(ID_WINDOW_TILE_VERT
, &CMDIFrameWnd::OnMDIWindowCmd
)
29 ON_UPDATE_COMMAND_UI(ID_WINDOW_NEW
, &CMDIFrameWnd::OnUpdateMDIWindowCmd
)
30 ON_COMMAND(ID_WINDOW_NEW
, &CMDIFrameWnd::OnWindowNew
)
32 ON_MESSAGE(WM_COMMANDHELP
, &CMDIFrameWnd::OnCommandHelp
)
36 CMDIFrameWnd::CMDIFrameWnd()
38 m_hWndMDIClient
= NULL
;
41 BOOL
CMDIFrameWnd::OnCommand(WPARAM wParam
, LPARAM lParam
)
43 // send to MDI child first - will be re-sent through OnCmdMsg later
44 CMDIChildWnd
* pActiveChild
= MDIGetActive();
45 if (pActiveChild
!= NULL
&& AfxCallWndProc(pActiveChild
,
46 pActiveChild
->m_hWnd
, WM_COMMAND
, wParam
, lParam
) != 0)
47 return TRUE
; // handled by child
49 if (CFrameWnd::OnCommand(wParam
, lParam
))
50 return TRUE
; // handled through normal mechanism (MDI child or frame)
52 HWND hWndCtrl
= (HWND
)lParam
;
54 ASSERT(AFX_IDM_FIRST_MDICHILD
== 0xFF00);
55 if (hWndCtrl
== NULL
&& (LOWORD(wParam
) & 0xf000) == 0xf000)
57 // menu or accelerator within range of MDI children
58 // default frame proc will handle it
59 DefWindowProc(WM_COMMAND
, wParam
, lParam
);
63 return FALSE
; // not handled
66 BOOL
CMDIFrameWnd::OnCmdMsg(UINT nID
, int nCode
, void* pExtra
,
67 AFX_CMDHANDLERINFO
* pHandlerInfo
)
69 CMDIChildWnd
* pActiveChild
= MDIGetActive();
70 // pump through active child FIRST
71 if (pActiveChild
!= NULL
)
73 CPushRoutingFrame
push(this);
74 if (pActiveChild
->OnCmdMsg(nID
, nCode
, pExtra
, pHandlerInfo
))
78 // then pump through normal frame
79 return CFrameWnd::OnCmdMsg(nID
, nCode
, pExtra
, pHandlerInfo
);
82 LRESULT
CMDIFrameWnd::OnCommandHelp(WPARAM wParam
, LPARAM lParam
)
84 if (lParam
== 0 && IsTracking())
85 #if (_MSC_VER == 1700)
86 lParam
= HID_BASE_COMMAND
+ GetTrackingID();
88 lParam
= HID_BASE_COMMAND
+m_nIDTracking
;
91 CMDIChildWnd
* pActiveChild
= MDIGetActive();
92 if (pActiveChild
!= NULL
&& AfxCallWndProc(pActiveChild
,
93 pActiveChild
->m_hWnd
, WM_COMMANDHELP
, wParam
, lParam
) != 0)
99 if (CFrameWnd::OnCommandHelp(wParam
, lParam
))
101 // handled by our base
107 CWinApp
* pApp
= AfxGetApp();
110 AfxGetApp()->WinHelpInternal(lParam
);
117 BOOL
CMDIFrameWnd::OnCreateClient(LPCREATESTRUCT lpcs
, CCreateContext
*)
120 if (m_hMenuDefault
== NULL
)
122 // default implementation for MFC V1 backward compatibility
124 ASSERT(pMenu
!= NULL
);
125 // This is attempting to guess which sub-menu is the Window menu.
126 // The Windows user interface guidelines say that the right-most
127 // menu on the menu bar should be Help and Window should be one
128 // to the left of that.
129 int iMenu
= pMenu
->GetMenuItemCount() - 2;
131 // If this assertion fails, your menu bar does not follow the guidelines
132 // so you will have to override this function and call CreateClient
133 // appropriately or use the MFC V2 MDI functionality.
135 pMenu
= pMenu
->GetSubMenu(iMenu
);
136 ASSERT(pMenu
!= NULL
);
139 return CreateClient(lpcs
, pMenu
);
142 BOOL
CMDIFrameWnd::CreateClient(LPCREATESTRUCT lpCreateStruct
,
145 ASSERT(m_hWnd
!= NULL
);
146 ASSERT(m_hWndMDIClient
== NULL
);
147 DWORD dwStyle
= WS_VISIBLE
| WS_CHILD
| WS_BORDER
|
148 WS_CLIPCHILDREN
| WS_CLIPSIBLINGS
|
149 MDIS_ALLCHILDSTYLES
; // allow children to be created invisible
151 // will be inset by the frame
153 // special styles for 3d effect on Win4
154 dwStyle
&= ~WS_BORDER
;
155 dwExStyle
= WS_EX_CLIENTEDGE
;
157 CLIENTCREATESTRUCT ccs
;
158 ccs
.hWindowMenu
= pWindowMenu
->GetSafeHmenu();
159 // set hWindowMenu for MFC V1 backward compatibility
160 // for MFC V2, window menu will be set in OnMDIActivate
161 ccs
.idFirstChild
= AFX_IDM_FIRST_MDICHILD
;
163 if (lpCreateStruct
->style
& (WS_HSCROLL
|WS_VSCROLL
))
165 // parent MDIFrame's scroll styles move to the MDICLIENT
166 dwStyle
|= (lpCreateStruct
->style
& (WS_HSCROLL
|WS_VSCROLL
));
168 // fast way to turn off the scrollbar bits (without a resize)
169 ModifyStyle(WS_HSCROLL
|WS_VSCROLL
, 0, SWP_NOREDRAW
|SWP_FRAMECHANGED
);
172 // Create MDICLIENT control with special IDC
173 #if (_MSC_VER == 1700)
174 if ((m_hWndMDIClient
= CreateWindowEx(dwExStyle
, _T("mdiclient"), NULL
,
175 dwStyle
, 0, 0, 0, 0, m_hWnd
, (HMENU
)AFX_IDW_PANE_FIRST
,
176 AfxGetInstanceHandle(), (LPVOID
)&ccs
)) == NULL
)
178 if ((m_hWndMDIClient
= ::AfxCtxCreateWindowEx(dwExStyle
, _T("mdiclient"), NULL
,
179 dwStyle
, 0, 0, 0, 0, m_hWnd
, (HMENU
)AFX_IDW_PANE_FIRST
,
180 AfxGetInstanceHandle(), (LPVOID
)&ccs
)) == NULL
)
183 TRACE(traceAppMsg
, 0, _T("Warning: CMDIFrameWnd::OnCreateClient: failed to create MDICLIENT.")
184 _T(" GetLastError returns 0x%8.8X\n"), ::GetLastError());
187 // Move it to the top of z-order
188 ::BringWindowToTop(m_hWndMDIClient
);
193 LRESULT
CMDIFrameWnd::DefWindowProc(UINT nMsg
, WPARAM wParam
, LPARAM lParam
)
195 return ::DefFrameProc(m_hWnd
, m_hWndMDIClient
, nMsg
, wParam
, lParam
);
198 BOOL
CMDIFrameWnd::PreTranslateMessage(MSG
* pMsg
)
200 // check for special cancel modes for ComboBoxes
201 if (pMsg
->message
== WM_LBUTTONDOWN
|| pMsg
->message
== WM_NCLBUTTONDOWN
)
202 AfxCancelModes(pMsg
->hwnd
); // filter clicks
204 // allow tooltip messages to be filtered
205 if (CWnd::PreTranslateMessage(pMsg
))
208 #ifndef _AFX_NO_OLE_SUPPORT
209 // allow hook to consume message
210 if (m_pNotifyHook
!= NULL
&& m_pNotifyHook
->OnPreTranslateMessage(pMsg
))
214 CMDIChildWnd
* pActiveChild
= MDIGetActive();
216 // current active child gets first crack at it
217 if (pActiveChild
!= NULL
&& pActiveChild
->PreTranslateMessage(pMsg
))
220 if (pMsg
->message
>= WM_KEYFIRST
&& pMsg
->message
<= WM_KEYLAST
)
222 // translate accelerators for frame and any children
223 if (m_hAccelTable
!= NULL
&&
224 ::TranslateAccelerator(m_hWnd
, m_hAccelTable
, pMsg
))
229 // special processing for MDI accelerators last
230 // and only if it is not in SDI mode (print preview)
231 if (GetActiveView() == NULL
)
233 if (pMsg
->message
== WM_KEYDOWN
|| pMsg
->message
== WM_SYSKEYDOWN
)
235 // the MDICLIENT window may translate it
236 if (::TranslateMDISysAccel(m_hWndMDIClient
, pMsg
))
245 void CMDIFrameWnd::DelayUpdateFrameMenu(HMENU hMenuAlt
)
247 OnUpdateFrameMenu(hMenuAlt
);
249 m_nIdleFlags
|= idleMenu
;
252 void CMDIFrameWnd::OnIdleUpdateCmdUI()
254 if (m_nIdleFlags
& idleMenu
)
257 m_nIdleFlags
&= ~idleMenu
;
259 CFrameWnd::OnIdleUpdateCmdUI();
262 CFrameWnd
* CMDIFrameWnd::GetActiveFrame()
264 CMDIChildWnd
* pActiveChild
= MDIGetActive();
265 if (pActiveChild
== NULL
)
270 BOOL
CMDIFrameWnd::PreCreateWindow(CREATESTRUCT
& cs
)
272 if (cs
.lpszClass
== NULL
)
274 VERIFY(AfxDeferRegisterClass(AFX_WNDMDIFRAME_REG
));
275 cs
.lpszClass
= _afxWndMDIFrame
;
280 BOOL
CMDIFrameWnd::LoadFrame(UINT nIDResource
, DWORD dwDefaultStyle
,
281 CWnd
* pParentWnd
, CCreateContext
* pContext
)
283 if (!CFrameWnd::LoadFrame(nIDResource
, dwDefaultStyle
,
284 pParentWnd
, pContext
))
287 // save menu to use when no active MDI child window is present
288 ASSERT(m_hWnd
!= NULL
);
289 m_hMenuDefault
= ::GetMenu(m_hWnd
);
293 void CMDIFrameWnd::OnDestroy()
295 CFrameWnd::OnDestroy(); // exit and misc cleanup
297 // owned menu stored in shared slot for MDIFRAME
298 if (m_hMenuDefault
!= NULL
&& ::GetMenu(m_hWnd
) != m_hMenuDefault
)
300 // must go through MDI client to get rid of MDI menu additions
301 ::SendMessage(m_hWndMDIClient
, WM_MDISETMENU
,
302 (WPARAM
)m_hMenuDefault
, NULL
);
303 ASSERT(::GetMenu(m_hWnd
) == m_hMenuDefault
);
307 void CMDIFrameWnd::OnSize(UINT nType
, int, int)
309 // do not call default - it will reposition the MDICLIENT
310 if (nType
!= SIZE_MINIMIZED
)
314 LRESULT
CMDIFrameWnd::OnMenuChar(UINT nChar
, UINT
, CMenu
*)
316 // do not call Default() for Alt+(-) when in print preview mode
317 if (m_lpfnCloseProc
!= NULL
&& nChar
== (UINT
)'-')
323 CMDIChildWnd
* CMDIFrameWnd::MDIGetActive(BOOL
* pbMaximized
) const
325 // check first for MDI client window not created
326 if (m_hWndMDIClient
== NULL
)
328 if (pbMaximized
!= NULL
)
329 *pbMaximized
= FALSE
;
333 // MDI client has been created, get active MDI child
334 HWND hWnd
= (HWND
)::SendMessage(m_hWndMDIClient
, WM_MDIGETACTIVE
, 0,
335 (LPARAM
)pbMaximized
);
336 CMDIChildWnd
* pWnd
= (CMDIChildWnd
*)CWnd::FromHandlePermanent(hWnd
);
337 ASSERT(pWnd
== NULL
|| pWnd
->IsKindOf(RUNTIME_CLASS(CMDIChildWnd
)));
339 // check for special pseudo-inactive state
340 if (pWnd
!= NULL
&& pWnd
->m_bPseudoInactive
&&
341 (pWnd
->GetStyle() & WS_VISIBLE
) == 0)
343 // Window is hidden, active, but m_bPseudoInactive -- return NULL
345 // Ignore maximized flag if pseudo-inactive and maximized
346 if (pbMaximized
!= NULL
)
347 *pbMaximized
= FALSE
;
353 CMDIChildWnd
* CMDIFrameWnd::CreateNewChild(CRuntimeClass
* pClass
,
354 UINT nResources
, HMENU hMenu
/* = NULL */, HACCEL hAccel
/* = NULL */)
356 ASSERT(pClass
!= NULL
);
357 CMDIChildWnd
* pFrame
= (CMDIChildWnd
*) pClass
->CreateObject();
358 ASSERT_KINDOF(CMDIChildWnd
, pFrame
);
361 CCreateContext context
;
362 context
.m_pCurrentFrame
= this;
364 pFrame
->SetHandles(hMenu
, hAccel
);
365 if (!pFrame
->LoadFrame(nResources
,
366 WS_OVERLAPPEDWINDOW
| FWS_ADDTOTITLE
, NULL
, &context
))
368 TRACE(traceAppMsg
, 0, "Couldn't load frame window.\n");
372 CString strFullString
, strTitle
;
373 if (strFullString
.LoadString(nResources
))
374 AfxExtractSubString(strTitle
, strFullString
, CDocTemplate::docName
);
376 // redraw the frame and parent
377 pFrame
->SetTitle(strTitle
);
378 pFrame
->InitialUpdateFrame(NULL
, TRUE
);
383 /////////////////////////////////////////////////////////////////////////////
384 // CMDIFrameWnd Diagnostics
387 void CMDIFrameWnd::AssertValid() const
389 CFrameWnd::AssertValid();
390 ASSERT(m_hWndMDIClient
== NULL
|| ::IsWindow(m_hWndMDIClient
));
391 ASSERT(m_hMenuDefault
== NULL
|| ::IsMenu(m_hMenuDefault
));
394 void CMDIFrameWnd::Dump(CDumpContext
& dc
) const
398 dc
<< "m_hWndMDIClient = " << (void*)m_hWndMDIClient
;
399 dc
<< "\nm_hMenuDefault = " << (void*)m_hMenuDefault
;
405 /////////////////////////////////////////////////////////////////////////////
408 BEGIN_MESSAGE_MAP(CMDIChildWnd
, CFrameWnd
)
409 ON_WM_MOUSEACTIVATE()
413 ON_WM_WINDOWPOSCHANGING()
417 ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTW
, 0, 0xFFFF, &CMDIChildWnd::OnToolTipText
)
418 ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTA
, 0, 0xFFFF, &CMDIChildWnd::OnToolTipText
)
421 CMDIChildWnd::CMDIChildWnd()
423 m_hMenuShared
= NULL
;
424 m_bPseudoInactive
= FALSE
;
427 /////////////////////////////////////////////////////////////////////////////
428 // CMDIChildWnd special processing
430 LRESULT
CMDIChildWnd::DefWindowProc(UINT nMsg
, WPARAM wParam
, LPARAM lParam
)
432 return ::DefMDIChildProc(m_hWnd
, nMsg
, wParam
, lParam
);
435 BOOL
CMDIChildWnd::DestroyWindow()
440 // avoid changing the caption during the destroy message(s)
441 CMDIFrameWnd
* pFrameWnd
= GetMDIFrame();
442 HWND hWndFrame
= pFrameWnd
->m_hWnd
;
443 ASSERT(::IsWindow(hWndFrame
));
444 DWORD dwStyle
= SetWindowLong(hWndFrame
, GWL_STYLE
,
445 GetWindowLong(hWndFrame
, GWL_STYLE
) & ~FWS_ADDTOTITLE
);
449 if (::IsWindow(hWndFrame
))
451 ASSERT(hWndFrame
== pFrameWnd
->m_hWnd
);
452 SetWindowLong(hWndFrame
, GWL_STYLE
, dwStyle
);
453 pFrameWnd
->OnUpdateFrameTitle(TRUE
);
459 BOOL
CMDIChildWnd::PreTranslateMessage(MSG
* pMsg
)
461 // check for special cancel modes for combo boxes
462 if (pMsg
->message
== WM_LBUTTONDOWN
|| pMsg
->message
== WM_NCLBUTTONDOWN
)
463 AfxCancelModes(pMsg
->hwnd
); // filter clicks
465 // allow tooltip messages to be filtered
466 if (CWnd::PreTranslateMessage(pMsg
))
469 // we can't call 'CFrameWnd::PreTranslate' since it will translate
470 // accelerators in the context of the MDI Child - but since MDI Child
471 // windows don't have menus this doesn't work properly. MDI Child
472 // accelerators must be translated in context of their MDI Frame.
474 if (pMsg
->message
>= WM_KEYFIRST
&& pMsg
->message
<= WM_KEYLAST
)
476 // use document specific accelerator table over m_hAccelTable
477 HACCEL hAccel
= GetDefaultAccelerator();
478 return hAccel
!= NULL
&&
479 ::TranslateAccelerator(GetMDIFrame()->m_hWnd
, hAccel
, pMsg
);
484 BOOL
CMDIChildWnd::PreCreateWindow(CREATESTRUCT
& cs
)
486 ASSERT(cs
.style
& WS_CHILD
);
487 // MFC V2 requires that MDI Children are created with proper styles,
488 // usually: WS_CHILD | WS_VISIBLE | WS_OVERLAPPEDWINDOW.
489 // See Technical note TN019 for more details on MFC V1->V2 migration.
491 return CFrameWnd::PreCreateWindow(cs
);
494 BOOL
CMDIChildWnd::Create(LPCTSTR lpszClassName
,
495 LPCTSTR lpszWindowName
, DWORD dwStyle
,
496 const RECT
& rect
, CMDIFrameWnd
* pParentWnd
,
497 CCreateContext
* pContext
)
499 if (pParentWnd
== NULL
)
501 CWinThread
*pThread
= AfxGetThread();
502 ENSURE_VALID(pThread
);
503 CWnd
* pMainWnd
= pThread
->m_pMainWnd
;
504 ENSURE_VALID(pMainWnd
);
505 ASSERT_KINDOF(CMDIFrameWnd
, pMainWnd
);
506 pParentWnd
= (CMDIFrameWnd
*)pMainWnd
;
508 ASSERT(::IsWindow(pParentWnd
->m_hWndMDIClient
));
510 // insure correct window positioning
511 pParentWnd
->RecalcLayout();
513 // first copy into a CREATESTRUCT for PreCreate
516 cs
.lpszClass
= lpszClassName
;
517 cs
.lpszName
= lpszWindowName
;
521 cs
.cx
= rect
.right
- rect
.left
;
522 cs
.cy
= rect
.bottom
- rect
.top
;
523 cs
.hwndParent
= pParentWnd
->m_hWnd
;
525 cs
.hInstance
= AfxGetInstanceHandle();
526 cs
.lpCreateParams
= (LPVOID
)pContext
;
528 if (!PreCreateWindow(cs
))
533 // extended style must be zero for MDI Children (except under Win4)
534 ASSERT(cs
.hwndParent
== pParentWnd
->m_hWnd
); // must not change
536 // now copy into a MDICREATESTRUCT for real create
538 mcs
.szClass
= cs
.lpszClass
;
539 mcs
.szTitle
= cs
.lpszName
;
540 mcs
.hOwner
= cs
.hInstance
;
545 mcs
.style
= cs
.style
& ~(WS_MAXIMIZE
| WS_VISIBLE
);
546 mcs
.lParam
= (LPARAM
)cs
.lpCreateParams
;
548 // create the window through the MDICLIENT window
549 AfxHookWindowCreate(this);
550 HWND hWnd
= (HWND
)::SendMessage(pParentWnd
->m_hWndMDIClient
,
551 WM_MDICREATE
, 0, (LPARAM
)&mcs
);
552 if (!AfxUnhookWindowCreate())
553 PostNcDestroy(); // cleanup if MDICREATE fails too soon
558 // special handling of visibility (always created invisible)
559 if (cs
.style
& WS_VISIBLE
)
561 // place the window on top in z-order before showing it
562 ::BringWindowToTop(hWnd
);
564 // show it as specified
565 if (cs
.style
& WS_MINIMIZE
)
566 ShowWindow(SW_SHOWMINIMIZED
);
567 else if (cs
.style
& WS_MAXIMIZE
)
568 ShowWindow(SW_SHOWMAXIMIZED
);
570 ShowWindow(SW_SHOWNORMAL
);
572 // make sure it is active (visibility == activation)
573 pParentWnd
->MDIActivate(this);
575 // refresh MDI Window menu
576 ::SendMessage(pParentWnd
->m_hWndMDIClient
, WM_MDIREFRESHMENU
, 0, 0);
579 ASSERT(hWnd
== m_hWnd
);
583 BOOL
CMDIChildWnd::LoadFrame(UINT nIDResource
, DWORD dwDefaultStyle
,
584 CWnd
* pParentWnd
, CCreateContext
* pContext
)
587 ASSERT_VALID_IDR(nIDResource
);
588 ASSERT(m_nIDHelp
== 0 || m_nIDHelp
== nIDResource
);
590 m_nIDHelp
= nIDResource
; // ID for help context (+HID_BASE_RESOURCE)
592 // parent must be MDI Frame (or NULL for default)
593 ASSERT(pParentWnd
== NULL
|| pParentWnd
->IsKindOf(RUNTIME_CLASS(CMDIFrameWnd
)));
594 // will be a child of MDIClient
595 ASSERT(!(dwDefaultStyle
& WS_POPUP
));
596 dwDefaultStyle
|= WS_CHILD
;
598 // if available - get MDI child menus from doc template
599 CMultiDocTemplate
* pTemplate
;
600 if (pContext
!= NULL
&&
601 (pTemplate
= (CMultiDocTemplate
*)pContext
->m_pNewDocTemplate
) != NULL
)
603 ASSERT_KINDOF(CMultiDocTemplate
, pTemplate
);
604 // get shared menu from doc template
605 m_hMenuShared
= pTemplate
->m_hMenuShared
;
606 m_hAccelTable
= pTemplate
->m_hAccelTable
;
610 TRACE(traceAppMsg
, 0, "Warning: no shared menu/acceltable for MDI Child window.\n");
611 // if this happens, programmer must load these manually
614 CString strFullString
, strTitle
;
615 if (strFullString
.LoadString(nIDResource
))
616 AfxExtractSubString(strTitle
, strFullString
, 0); // first sub-string
618 ASSERT(m_hWnd
== NULL
);
619 if (!Create(GetIconWndClass(dwDefaultStyle
, nIDResource
),
620 strTitle
, dwDefaultStyle
, rectDefault
,
621 (CMDIFrameWnd
*)pParentWnd
, pContext
))
623 return FALSE
; // will self destruct on failure normally
630 void CMDIChildWnd::OnSize(UINT nType
, int cx
, int cy
)
632 CFrameWnd::OnSize(nType
, cx
, cy
);
634 // update our parent frame - in case we are now maximized or not
635 GetMDIFrame()->OnUpdateFrameTitle(TRUE
);
638 BOOL
CMDIChildWnd::UpdateClientEdge(LPRECT lpRect
)
640 // only adjust for active MDI child window
641 CMDIFrameWnd
* pFrameWnd
= GetMDIFrame();
642 CMDIChildWnd
* pChild
= pFrameWnd
->MDIGetActive();
644 // Only adjust for regular MDI child windows, not tabbed windows. Attempting to set WS_EX_CLIENTEDGE on the tabbed
645 // MDI client area window is subverted by CMDIClientAreaWnd::OnStyleChanging, so we always try to reset the style and
646 // always repaint, none of which is necessary since the tabbed MDI children never change from maximized to restored.
648 if ((pChild
== NULL
|| pChild
== this) /*&& !bIsTabbedMDIChild*/)
650 // need to adjust the client edge style as max/restore happens
651 DWORD dwStyle
= ::GetWindowLong(pFrameWnd
->m_hWndMDIClient
, GWL_EXSTYLE
);
652 DWORD dwNewStyle
= dwStyle
;
653 if (pChild
!= NULL
&& !(GetExStyle() & WS_EX_CLIENTEDGE
) && (GetStyle() & WS_MAXIMIZE
))
655 dwNewStyle
&= ~(WS_EX_CLIENTEDGE
);
659 dwNewStyle
|= WS_EX_CLIENTEDGE
;
662 if (dwStyle
!= dwNewStyle
)
664 // SetWindowPos will not move invalid bits
665 ::RedrawWindow(pFrameWnd
->m_hWndMDIClient
, NULL
, NULL
, RDW_INVALIDATE
| RDW_ALLCHILDREN
);
667 // remove/add WS_EX_CLIENTEDGE to MDI client area
668 ::SetWindowLong(pFrameWnd
->m_hWndMDIClient
, GWL_EXSTYLE
, dwNewStyle
);
669 ::SetWindowPos(pFrameWnd
->m_hWndMDIClient
, NULL
, 0, 0, 0, 0, SWP_FRAMECHANGED
| SWP_NOACTIVATE
| SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOZORDER
| SWP_NOCOPYBITS
);
671 // return new client area
674 ::GetClientRect(pFrameWnd
->m_hWndMDIClient
, lpRect
);
684 void CMDIChildWnd::OnWindowPosChanging(LPWINDOWPOS lpWndPos
)
686 if (!(lpWndPos
->flags
& SWP_NOSIZE
))
689 if (UpdateClientEdge(rectClient
) && (GetStyle() & WS_MAXIMIZE
))
691 // adjust maximized window size and position based on new
692 // size/position of the MDI client area.
693 ::AdjustWindowRectEx(rectClient
, GetStyle(), FALSE
, GetExStyle());
694 lpWndPos
->x
= rectClient
.left
;
695 lpWndPos
->y
= rectClient
.top
;
696 lpWndPos
->cx
= rectClient
.Width();
697 lpWndPos
->cy
= rectClient
.Height();
701 CFrameWnd::OnWindowPosChanging(lpWndPos
);
704 void CMDIChildWnd::OnDestroy()
708 CFrameWnd::OnDestroy();
711 BOOL
CMDIChildWnd::OnNcActivate(BOOL bActive
)
713 // bypass CFrameWnd::OnNcActivate()
714 return CWnd::OnNcActivate(bActive
);
717 int CMDIChildWnd::OnMouseActivate(CWnd
* pDesktopWnd
, UINT nHitTest
, UINT message
)
719 int nResult
= CFrameWnd::OnMouseActivate(pDesktopWnd
, nHitTest
, message
);
720 if (nResult
== MA_NOACTIVATE
|| nResult
== MA_NOACTIVATEANDEAT
)
721 return nResult
; // frame does not want to activate
723 // activate this window if necessary
724 CMDIFrameWnd
* pFrameWnd
= GetMDIFrame();
725 ENSURE_VALID(pFrameWnd
);
726 CMDIChildWnd
* pActive
= pFrameWnd
->MDIGetActive();
733 BOOL
CMDIChildWnd::OnToolTipText(UINT msg
, NMHDR
* pNMHDR
, LRESULT
* pResult
)
735 ASSERT(pNMHDR
->code
== TTN_NEEDTEXTA
|| pNMHDR
->code
== TTN_NEEDTEXTW
);
738 // check to see if the message is going directly to this window or not
739 const MSG
* pMsg
= GetCurrentMessage();
740 if (pMsg
->hwnd
!= m_hWnd
)
742 // let top level frame handle this for us
746 // otherwise, handle it ourselves
747 return CFrameWnd::OnToolTipText(msg
, pNMHDR
, pResult
);
750 void CMDIChildWnd::ActivateFrame(int nCmdShow
)
752 BOOL bVisibleThen
= (GetStyle() & WS_VISIBLE
) != 0;
753 CMDIFrameWnd
* pFrameWnd
= GetMDIFrame();
754 ASSERT_VALID(pFrameWnd
);
756 // determine default show command
759 // get maximized state of frame window (previously active child)
761 pFrameWnd
->MDIGetActive(&bMaximized
);
763 // convert show command based on current style
764 DWORD dwStyle
= GetStyle();
765 if (bMaximized
|| (dwStyle
& WS_MAXIMIZE
))
766 nCmdShow
= SW_SHOWMAXIMIZED
;
767 else if (dwStyle
& WS_MINIMIZE
)
768 nCmdShow
= SW_SHOWMINIMIZED
;
771 // finally, show the window
772 CFrameWnd::ActivateFrame(nCmdShow
);
774 // update the Window menu to reflect new child window
775 CMDIFrameWnd
* pFrame
= GetMDIFrame();
776 ::SendMessage(pFrame
->m_hWndMDIClient
, WM_MDIREFRESHMENU
, 0, 0);
778 // Note: Update the m_bPseudoInactive flag. This is used to handle the
779 // last MDI child getting hidden. Windows provides no way to deactivate
780 // an MDI child window.
782 BOOL bVisibleNow
= (GetStyle() & WS_VISIBLE
) != 0;
783 if (bVisibleNow
== bVisibleThen
)
788 // get current active window according to Windows MDI
789 HWND hWnd
= (HWND
)::SendMessage(pFrameWnd
->m_hWndMDIClient
,
790 WM_MDIGETACTIVE
, 0, 0);
793 // not active any more -- window must have been deactivated
794 ASSERT(!m_bPseudoInactive
);
799 ASSERT(hWnd
!= NULL
);
800 pFrameWnd
->MDINext();
802 // see if it has been deactivated now...
803 hWnd
= (HWND
)::SendMessage(pFrameWnd
->m_hWndMDIClient
,
804 WM_MDIGETACTIVE
, 0, 0);
807 // still active -- fake deactivate it
808 ASSERT(hWnd
!= NULL
);
809 ::SendMessage(pFrameWnd
->m_hWndMDIClient
, WM_MDIACTIVATE
, (WPARAM
)m_hWnd
, NULL
);
810 m_bPseudoInactive
= TRUE
; // so MDIGetActive returns NULL
813 else if (m_bPseudoInactive
)
815 // if state transitioned from not visible to visible, but
816 // was pseudo deactivated -- send activate notify now
817 ::SendMessage(pFrameWnd
->m_hWndMDIClient
, WM_MDIACTIVATE
, NULL
, (LPARAM
)m_hWnd
);
818 ASSERT(!m_bPseudoInactive
); // should get set in OnMDIActivate!
822 void CMDIChildWnd::SetHandles(HMENU hMenu
, HACCEL hAccel
)
824 m_hMenuShared
= hMenu
;
825 m_hAccelTable
= hAccel
;
828 #if (_MSC_VER == 1700)
829 UINT
CMDIChildWnd::GetTrackingID()
831 if (GetParentFrame() && GetParentFrame()->IsTracking())
833 return GetParentFrame()->GetTrackingID();
836 return m_nIDTracking
;
840 /////////////////////////////////////////////////////////////////////////////
841 // CMDIChildWnd Diagnostics
844 void CMDIChildWnd::AssertValid() const
846 CFrameWnd::AssertValid();
847 ASSERT(m_hMenuShared
== NULL
|| ::IsMenu(m_hMenuShared
));
850 void CMDIChildWnd::Dump(CDumpContext
& dc
) const
854 dc
<< "m_hMenuShared = " << (void*)m_hMenuShared
;
859 /////////////////////////////////////////////////////////////////////////////
860 // Smarts for the "Window" menu
862 HMENU
CMDIFrameWnd::GetWindowMenuPopup(HMENU hMenuBar
)
863 // find which popup is the "Window" menu
865 if (hMenuBar
== NULL
)
868 ASSERT(::IsMenu(hMenuBar
));
870 int iItem
= ::GetMenuItemCount(hMenuBar
);
873 HMENU hMenuPop
= ::GetSubMenu(hMenuBar
, iItem
);
874 if (hMenuPop
!= NULL
)
876 int iItemMax
= ::GetMenuItemCount(hMenuPop
);
877 for (int iItemPop
= 0; iItemPop
< iItemMax
; iItemPop
++)
879 UINT nID
= GetMenuItemID(hMenuPop
, iItemPop
);
880 if (nID
>= AFX_IDM_WINDOW_FIRST
&& nID
<= AFX_IDM_WINDOW_LAST
)
886 // no default menu found
887 TRACE(traceAppMsg
, 0, "Warning: GetWindowMenuPopup failed!\n");
891 /////////////////////////////////////////////////////////////////////////////
892 // Smarts for updating the window menu based on the current child
894 void CMDIFrameWnd::OnUpdateFrameMenu(HMENU hMenuAlt
)
896 CMDIChildWnd
* pActiveWnd
= MDIGetActive();
897 if (pActiveWnd
!= NULL
)
899 // let child update the menu bar
900 pActiveWnd
->OnUpdateFrameMenu(TRUE
, pActiveWnd
, hMenuAlt
);
904 // no child active, so have to update it ourselves
905 // (we can't send it to a child window, since pActiveWnd is NULL)
906 if (hMenuAlt
== NULL
)
907 hMenuAlt
= m_hMenuDefault
; // use default
908 ::SendMessage(m_hWndMDIClient
, WM_MDISETMENU
, (WPARAM
)hMenuAlt
, NULL
);
912 /////////////////////////////////////////////////////////////////////////////
913 // MDI Child Extensions
915 // walk up two parents for MDIFrame that owns MDIChild (skip MDIClient)
916 CMDIFrameWnd
* CMDIChildWnd::GetMDIFrame()
918 ASSERT_KINDOF(CMDIChildWnd
, this);
919 ASSERT(m_hWnd
!= NULL
);
920 HWND hWndMDIClient
= ::GetParent(m_hWnd
);
921 ASSERT(hWndMDIClient
!= NULL
);
923 CMDIFrameWnd
* pMDIFrame
;
924 pMDIFrame
= (CMDIFrameWnd
*)CWnd::FromHandle(::GetParent(hWndMDIClient
));
925 ASSERT(pMDIFrame
!= NULL
);
926 ASSERT_KINDOF(CMDIFrameWnd
, pMDIFrame
);
927 ASSERT(pMDIFrame
->m_hWndMDIClient
== hWndMDIClient
);
928 ASSERT_VALID(pMDIFrame
);
932 CWnd
* CMDIChildWnd::GetMessageBar()
934 // status bar/message bar owned by parent MDI frame
935 return GetMDIFrame()->GetMessageBar();
938 void CMDIChildWnd::OnUpdateFrameTitle(BOOL bAddToTitle
)
940 // update our parent window first
941 GetMDIFrame()->OnUpdateFrameTitle(bAddToTitle
);
943 if ((GetStyle() & FWS_ADDTOTITLE
) == 0)
944 return; // leave child window alone!
946 CDocument
* pDocument
= GetActiveDocument();
949 TCHAR szText
[256+_MAX_PATH
];
950 if (pDocument
== NULL
)
951 Checked::tcsncpy_s(szText
, _countof(szText
), m_strTitle
, _TRUNCATE
);
953 Checked::tcsncpy_s(szText
, _countof(szText
), pDocument
->GetTitle(), _TRUNCATE
);
956 TCHAR szWinNumber
[16+1];
957 _stprintf_s(szWinNumber
, _countof(szWinNumber
), _T(":%d"), m_nWindow
);
959 if( _tcslen(szText
) + _tcslen(szWinNumber
) < _countof(szText
) )
961 Checked::tcscat_s( szText
, _countof(szText
), szWinNumber
);
965 // set title if changed, but don't remove completely
966 AfxSetWindowText(m_hWnd
, szText
);
970 void CMDIChildWnd::OnMDIActivate(BOOL bActivate
, CWnd
* pActivateWnd
, CWnd
*)
972 m_bPseudoInactive
= FALSE
; // must be happening for real
974 // make sure MDI client window has correct client edge
977 // send deactivate notification to active view
978 CView
* pActiveView
= GetActiveView();
979 if (!bActivate
&& pActiveView
!= NULL
)
980 pActiveView
->OnActivateView(FALSE
, pActiveView
, pActiveView
);
982 // allow hook to short circuit normal activation
983 BOOL bHooked
= FALSE
;
984 #ifndef _AFX_NO_OLE_SUPPORT
985 if (m_pNotifyHook
!= NULL
&& m_pNotifyHook
->OnDocActivate(bActivate
))
989 // update titles (don't AddToTitle if deactivate last)
991 OnUpdateFrameTitle(bActivate
|| (pActivateWnd
!= NULL
));
993 // re-activate the appropriate view
996 if (pActiveView
!= NULL
&& GetMDIFrame() == GetActiveWindow())
997 pActiveView
->OnActivateView(TRUE
, pActiveView
, pActiveView
);
1003 OnUpdateFrameMenu(bActivate
, pActivateWnd
, NULL
);
1004 GetMDIFrame()->DrawMenuBar();
1008 void CMDIChildWnd::OnUpdateFrameMenu(BOOL bActivate
, CWnd
* pActivateWnd
,
1011 CMDIFrameWnd
* pFrame
= GetMDIFrame();
1013 if (hMenuAlt
== NULL
&& bActivate
)
1015 // attempt to get default menu from document
1016 CDocument
* pDoc
= GetActiveDocument();
1018 hMenuAlt
= pDoc
->GetDefaultMenu();
1021 // use default menu stored in frame if none from document
1022 if (hMenuAlt
== NULL
)
1023 hMenuAlt
= m_hMenuShared
;
1025 if (hMenuAlt
!= NULL
&& bActivate
)
1027 ASSERT(pActivateWnd
== this);
1029 // activating child, set parent menu
1030 ::SendMessage(pFrame
->m_hWndMDIClient
, WM_MDISETMENU
,
1031 (WPARAM
)hMenuAlt
, (LPARAM
)pFrame
->GetWindowMenuPopup(hMenuAlt
));
1033 else if (hMenuAlt
!= NULL
&& !bActivate
&& pActivateWnd
== NULL
)
1035 // destroying last child
1036 HMENU hMenuLast
= NULL
;
1037 ::SendMessage(pFrame
->m_hWndMDIClient
, WM_MDISETMENU
,
1038 (WPARAM
)pFrame
->m_hMenuDefault
, (LPARAM
)hMenuLast
);
1042 // refresh MDI Window menu (even if non-shared menu)
1043 ::SendMessage(pFrame
->m_hWndMDIClient
, WM_MDIREFRESHMENU
, 0, 0);
1047 BOOL
CMDIChildWnd::OnNcCreate(LPCREATESTRUCT lpCreateStruct
)
1049 if (!CFrameWnd::OnNcCreate(lpCreateStruct
))
1052 // handle extended styles under Win4
1053 // call PreCreateWindow again just to get dwExStyle
1054 VERIFY(PreCreateWindow(*lpCreateStruct
));
1055 SetWindowLong(m_hWnd
, GWL_EXSTYLE
, lpCreateStruct
->dwExStyle
);
1060 int CMDIChildWnd::OnCreate(LPCREATESTRUCT lpCreateStruct
)
1062 // call base class with lParam context (not MDI one)
1063 MDICREATESTRUCT
* lpmcs
;
1064 lpmcs
= (MDICREATESTRUCT
*)lpCreateStruct
->lpCreateParams
;
1065 CCreateContext
* pContext
= (CCreateContext
*)lpmcs
->lParam
;
1067 return OnCreateHelper(lpCreateStruct
, pContext
);
1070 /////////////////////////////////////////////////////////////////////////////
1071 // Special UI processing depending on current active child
1073 void CMDIFrameWnd::OnUpdateFrameTitle(BOOL bAddToTitle
)
1075 if ((GetStyle() & FWS_ADDTOTITLE
) == 0)
1076 return; // leave it alone!
1078 #ifndef _AFX_NO_OLE_SUPPORT
1079 // allow hook to set the title (used for OLE support)
1080 if (m_pNotifyHook
!= NULL
&& m_pNotifyHook
->OnUpdateFrameTitle())
1084 CMDIChildWnd
* pActiveChild
= NULL
;
1085 CDocument
* pDocument
= GetActiveDocument();
1087 (pActiveChild
= MDIGetActive()) != NULL
&&
1088 (pActiveChild
->GetStyle() & WS_MAXIMIZE
) == 0 &&
1089 (pDocument
!= NULL
||
1090 (pDocument
= pActiveChild
->GetActiveDocument()) != NULL
))
1091 UpdateFrameTitleForDocument(pDocument
->GetTitle());
1094 LPCTSTR lpstrTitle
= NULL
;
1097 if (pActiveChild
!= NULL
&&
1098 (pActiveChild
->GetStyle() & WS_MAXIMIZE
) == 0)
1100 strTitle
= pActiveChild
->GetTitle();
1101 if (!strTitle
.IsEmpty())
1102 lpstrTitle
= strTitle
;
1104 UpdateFrameTitleForDocument(lpstrTitle
);
1108 /////////////////////////////////////////////////////////////////////////////
1109 // Standard MDI Commands
1111 // Two function for all standard MDI "Window" commands
1112 void CMDIFrameWnd::OnUpdateMDIWindowCmd(CCmdUI
* pCmdUI
)
1114 ASSERT(m_hWndMDIClient
!= NULL
);
1115 pCmdUI
->Enable(MDIGetActive() != NULL
);
1118 BOOL
CMDIFrameWnd::OnMDIWindowCmd(UINT nID
)
1120 ASSERT(m_hWndMDIClient
!= NULL
);
1127 return FALSE
; // not for us
1128 case ID_WINDOW_ARRANGE
:
1129 msg
= WM_MDIICONARRANGE
;
1131 case ID_WINDOW_CASCADE
:
1132 msg
= WM_MDICASCADE
;
1134 case ID_WINDOW_TILE_HORZ
:
1135 wParam
= MDITILE_HORIZONTAL
;
1137 case ID_WINDOW_TILE_VERT
:
1138 ASSERT(MDITILE_VERTICAL
== 0);
1143 ::SendMessage(m_hWndMDIClient
, msg
, wParam
, 0);
1147 void CMDIFrameWnd::OnWindowNew()
1149 CMDIChildWnd
* pActiveChild
= MDIGetActive();
1150 CDocument
* pDocument
;
1151 if (pActiveChild
== NULL
||
1152 (pDocument
= pActiveChild
->GetActiveDocument()) == NULL
)
1154 TRACE(traceAppMsg
, 0, "Warning: No active document for WindowNew command.\n");
1155 AfxMessageBox(AFX_IDP_COMMAND_FAILURE
);
1156 return; // command failed
1159 // otherwise we have a new frame !
1160 CDocTemplate
* pTemplate
= pDocument
->GetDocTemplate();
1161 ASSERT_VALID(pTemplate
);
1162 CFrameWnd
* pFrame
= pTemplate
->CreateNewFrame(pDocument
, pActiveChild
);
1165 TRACE(traceAppMsg
, 0, "Warning: failed to create new frame.\n");
1166 return; // command failed
1169 pTemplate
->InitialUpdateFrame(pFrame
, pDocument
);
1172 void CMDIFrameWnd::SetMenuBarVisibility(DWORD dwStyle
)
1174 ENSURE_ARG(dwStyle
== AFX_MBV_KEEPVISIBLE
);
1175 ASSERT(m_dwMenuBarVisibility
== AFX_MBV_KEEPVISIBLE
);
1178 BOOL
CMDIFrameWnd::SetMenuBarState(DWORD dwState
)
1180 return m_dwMenuBarState
== AFX_MBS_HIDDEN
? FALSE
: CFrameWnd::SetMenuBarState(dwState
);
1183 IMPLEMENT_DYNCREATE(CMDIFrameWnd
, CFrameWnd
)
1184 IMPLEMENT_DYNCREATE(CMDIChildWnd
, CFrameWnd
)
1186 ////////////////////////////////////////////////////////////////////////////