Visual Studio 2012 Support
[xy_vsfilter.git] / src / thirdparty / mfc / winmdi.cpp
blob6ea5318cf5d0b10595cb6def89b8f0fccafab062
1 // This is a part of the Microsoft Foundation Classes C++ library.
2 // Copyright (C) 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.
11 #include "stdafx.h"
12 //#include "afxmdichildwndex.h"
13 //#include "afxmdiframewndex.h"
15 /////////////////////////////////////////////////////////////////////////////
16 // CMDIFrameWnd
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)
24 ON_WM_SIZE()
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)
31 ON_WM_DESTROY()
32 ON_MESSAGE(WM_COMMANDHELP, &CMDIFrameWnd::OnCommandHelp)
33 ON_WM_MENUCHAR()
34 END_MESSAGE_MAP()
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);
60 return TRUE;
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))
75 return TRUE;
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();
87 #else
88 lParam = HID_BASE_COMMAND+m_nIDTracking;
89 #endif
91 CMDIChildWnd* pActiveChild = MDIGetActive();
92 if (pActiveChild != NULL && AfxCallWndProc(pActiveChild,
93 pActiveChild->m_hWnd, WM_COMMANDHELP, wParam, lParam) != 0)
95 // handled by child
96 return TRUE;
99 if (CFrameWnd::OnCommandHelp(wParam, lParam))
101 // handled by our base
102 return TRUE;
105 if (lParam != 0)
107 CWinApp* pApp = AfxGetApp();
108 if (pApp != NULL)
110 AfxGetApp()->WinHelpInternal(lParam);
111 return TRUE;
114 return FALSE;
117 BOOL CMDIFrameWnd::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext*)
119 CMenu* pMenu = NULL;
120 if (m_hMenuDefault == NULL)
122 // default implementation for MFC V1 backward compatibility
123 pMenu = GetMenu();
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.
134 ASSERT(iMenu >= 0);
135 pMenu = pMenu->GetSubMenu(iMenu);
136 ASSERT(pMenu != NULL);
139 return CreateClient(lpcs, pMenu);
142 BOOL CMDIFrameWnd::CreateClient(LPCREATESTRUCT lpCreateStruct,
143 CMenu* pWindowMenu)
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
150 DWORD dwExStyle = 0;
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)
177 #else
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)
181 #endif
183 TRACE(traceAppMsg, 0, _T("Warning: CMDIFrameWnd::OnCreateClient: failed to create MDICLIENT.")
184 _T(" GetLastError returns 0x%8.8X\n"), ::GetLastError());
185 return FALSE;
187 // Move it to the top of z-order
188 ::BringWindowToTop(m_hWndMDIClient);
190 return TRUE;
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))
206 return TRUE;
208 #ifndef _AFX_NO_OLE_SUPPORT
209 // allow hook to consume message
210 if (m_pNotifyHook != NULL && m_pNotifyHook->OnPreTranslateMessage(pMsg))
211 return TRUE;
212 #endif
214 CMDIChildWnd* pActiveChild = MDIGetActive();
216 // current active child gets first crack at it
217 if (pActiveChild != NULL && pActiveChild->PreTranslateMessage(pMsg))
218 return TRUE;
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))
226 return TRUE;
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))
237 return TRUE;
242 return FALSE;
245 void CMDIFrameWnd::DelayUpdateFrameMenu(HMENU hMenuAlt)
247 OnUpdateFrameMenu(hMenuAlt);
249 m_nIdleFlags |= idleMenu;
252 void CMDIFrameWnd::OnIdleUpdateCmdUI()
254 if (m_nIdleFlags & idleMenu)
256 DrawMenuBar();
257 m_nIdleFlags &= ~idleMenu;
259 CFrameWnd::OnIdleUpdateCmdUI();
262 CFrameWnd* CMDIFrameWnd::GetActiveFrame()
264 CMDIChildWnd* pActiveChild = MDIGetActive();
265 if (pActiveChild == NULL)
266 return this;
267 return pActiveChild;
270 BOOL CMDIFrameWnd::PreCreateWindow(CREATESTRUCT& cs)
272 if (cs.lpszClass == NULL)
274 VERIFY(AfxDeferRegisterClass(AFX_WNDMDIFRAME_REG));
275 cs.lpszClass = _afxWndMDIFrame;
277 return TRUE;
280 BOOL CMDIFrameWnd::LoadFrame(UINT nIDResource, DWORD dwDefaultStyle,
281 CWnd* pParentWnd, CCreateContext* pContext)
283 if (!CFrameWnd::LoadFrame(nIDResource, dwDefaultStyle,
284 pParentWnd, pContext))
285 return FALSE;
287 // save menu to use when no active MDI child window is present
288 ASSERT(m_hWnd != NULL);
289 m_hMenuDefault = ::GetMenu(m_hWnd);
290 return TRUE;
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)
311 RecalcLayout();
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)'-')
318 return 0;
319 else
320 return Default();
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;
330 return NULL;
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
344 pWnd = NULL;
345 // Ignore maximized flag if pseudo-inactive and maximized
346 if (pbMaximized != NULL)
347 *pbMaximized = FALSE;
349 return pWnd;
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);
360 // load the frame
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");
369 return NULL;
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);
380 return pFrame;
383 /////////////////////////////////////////////////////////////////////////////
384 // CMDIFrameWnd Diagnostics
386 #ifdef _DEBUG
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
396 CFrameWnd::Dump(dc);
398 dc << "m_hWndMDIClient = " << (void*)m_hWndMDIClient;
399 dc << "\nm_hMenuDefault = " << (void*)m_hMenuDefault;
401 dc << "\n";
403 #endif //_DEBUG
405 /////////////////////////////////////////////////////////////////////////////
406 // CMDIChildWnd
408 BEGIN_MESSAGE_MAP(CMDIChildWnd, CFrameWnd)
409 ON_WM_MOUSEACTIVATE()
410 ON_WM_NCACTIVATE()
411 ON_WM_MDIACTIVATE()
412 ON_WM_SIZE()
413 ON_WM_WINDOWPOSCHANGING()
414 ON_WM_NCCREATE()
415 ON_WM_CREATE()
416 ON_WM_DESTROY()
417 ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTW, 0, 0xFFFF, &CMDIChildWnd::OnToolTipText)
418 ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTA, 0, 0xFFFF, &CMDIChildWnd::OnToolTipText)
419 END_MESSAGE_MAP()
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()
437 if (m_hWnd == NULL)
438 return FALSE;
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);
447 MDIDestroy();
449 if (::IsWindow(hWndFrame))
451 ASSERT(hWndFrame == pFrameWnd->m_hWnd);
452 SetWindowLong(hWndFrame, GWL_STYLE, dwStyle);
453 pFrameWnd->OnUpdateFrameTitle(TRUE);
456 return 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))
467 return TRUE;
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);
481 return FALSE;
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
514 CREATESTRUCT cs;
515 cs.dwExStyle = 0L;
516 cs.lpszClass = lpszClassName;
517 cs.lpszName = lpszWindowName;
518 cs.style = dwStyle;
519 cs.x = rect.left;
520 cs.y = rect.top;
521 cs.cx = rect.right - rect.left;
522 cs.cy = rect.bottom - rect.top;
523 cs.hwndParent = pParentWnd->m_hWnd;
524 cs.hMenu = NULL;
525 cs.hInstance = AfxGetInstanceHandle();
526 cs.lpCreateParams = (LPVOID)pContext;
528 if (!PreCreateWindow(cs))
530 PostNcDestroy();
531 return FALSE;
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
537 MDICREATESTRUCT mcs;
538 mcs.szClass = cs.lpszClass;
539 mcs.szTitle = cs.lpszName;
540 mcs.hOwner = cs.hInstance;
541 mcs.x = cs.x;
542 mcs.y = cs.y;
543 mcs.cx = cs.cx;
544 mcs.cy = cs.cy;
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
555 if (hWnd == NULL)
556 return FALSE;
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);
569 else
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);
580 return TRUE;
583 BOOL CMDIChildWnd::LoadFrame(UINT nIDResource, DWORD dwDefaultStyle,
584 CWnd* pParentWnd, CCreateContext* pContext)
586 // only do this once
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;
608 else
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
626 // it worked !
627 return TRUE;
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);
657 else
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
672 if (lpRect != NULL)
674 ::GetClientRect(pFrameWnd->m_hWndMDIClient, lpRect);
677 return TRUE;
681 return FALSE;
684 void CMDIChildWnd::OnWindowPosChanging(LPWINDOWPOS lpWndPos)
686 if (!(lpWndPos->flags & SWP_NOSIZE))
688 CRect rectClient;
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()
706 UpdateClientEdge();
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();
727 if (pActive != this)
728 MDIActivate();
730 return nResult;
733 BOOL CMDIChildWnd::OnToolTipText(UINT msg, NMHDR* pNMHDR, LRESULT* pResult)
735 ASSERT(pNMHDR->code == TTN_NEEDTEXTA || pNMHDR->code == TTN_NEEDTEXTW);
736 UNUSED(pNMHDR);
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
743 return FALSE;
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
757 if (nCmdShow == -1)
759 // get maximized state of frame window (previously active child)
760 BOOL bMaximized;
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)
784 return;
786 if (!bVisibleNow)
788 // get current active window according to Windows MDI
789 HWND hWnd = (HWND)::SendMessage(pFrameWnd->m_hWndMDIClient,
790 WM_MDIGETACTIVE, 0, 0);
791 if (hWnd != m_hWnd)
793 // not active any more -- window must have been deactivated
794 ASSERT(!m_bPseudoInactive);
795 return;
798 // check next window
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);
805 if (hWnd == m_hWnd)
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;
838 #endif
840 /////////////////////////////////////////////////////////////////////////////
841 // CMDIChildWnd Diagnostics
843 #ifdef _DEBUG
844 void CMDIChildWnd::AssertValid() const
846 CFrameWnd::AssertValid();
847 ASSERT(m_hMenuShared == NULL || ::IsMenu(m_hMenuShared));
850 void CMDIChildWnd::Dump(CDumpContext& dc) const
852 CFrameWnd::Dump(dc);
854 dc << "m_hMenuShared = " << (void*)m_hMenuShared;
855 dc << "\n";
857 #endif //_DEBUG
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)
866 return NULL;
868 ASSERT(::IsMenu(hMenuBar));
870 int iItem = ::GetMenuItemCount(hMenuBar);
871 while (iItem--)
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)
881 return hMenuPop;
886 // no default menu found
887 TRACE(traceAppMsg, 0, "Warning: GetWindowMenuPopup failed!\n");
888 return NULL;
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);
902 else
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);
929 return 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();
947 if (bAddToTitle)
949 TCHAR szText[256+_MAX_PATH];
950 if (pDocument == NULL)
951 Checked::tcsncpy_s(szText, _countof(szText), m_strTitle, _TRUNCATE);
952 else
953 Checked::tcsncpy_s(szText, _countof(szText), pDocument->GetTitle(), _TRUNCATE);
954 if (m_nWindow > 0)
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
975 UpdateClientEdge();
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))
986 bHooked = TRUE;
987 #endif
989 // update titles (don't AddToTitle if deactivate last)
990 if (!bHooked)
991 OnUpdateFrameTitle(bActivate || (pActivateWnd != NULL));
993 // re-activate the appropriate view
994 if (bActivate)
996 if (pActiveView != NULL && GetMDIFrame() == GetActiveWindow())
997 pActiveView->OnActivateView(TRUE, pActiveView, pActiveView);
1000 // update menus
1001 if (!bHooked)
1003 OnUpdateFrameMenu(bActivate, pActivateWnd, NULL);
1004 GetMDIFrame()->DrawMenuBar();
1008 void CMDIChildWnd::OnUpdateFrameMenu(BOOL bActivate, CWnd* pActivateWnd,
1009 HMENU hMenuAlt)
1011 CMDIFrameWnd* pFrame = GetMDIFrame();
1013 if (hMenuAlt == NULL && bActivate)
1015 // attempt to get default menu from document
1016 CDocument* pDoc = GetActiveDocument();
1017 if (pDoc != NULL)
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);
1040 else
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))
1050 return FALSE;
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);
1057 return TRUE;
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())
1081 return;
1082 #endif
1084 CMDIChildWnd* pActiveChild = NULL;
1085 CDocument* pDocument = GetActiveDocument();
1086 if (bAddToTitle &&
1087 (pActiveChild = MDIGetActive()) != NULL &&
1088 (pActiveChild->GetStyle() & WS_MAXIMIZE) == 0 &&
1089 (pDocument != NULL ||
1090 (pDocument = pActiveChild->GetActiveDocument()) != NULL))
1091 UpdateFrameTitleForDocument(pDocument->GetTitle());
1092 else
1094 LPCTSTR lpstrTitle = NULL;
1095 CString strTitle;
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);
1122 UINT msg;
1123 UINT wParam = 0;
1124 switch (nID)
1126 default:
1127 return FALSE; // not for us
1128 case ID_WINDOW_ARRANGE:
1129 msg = WM_MDIICONARRANGE;
1130 break;
1131 case ID_WINDOW_CASCADE:
1132 msg = WM_MDICASCADE;
1133 break;
1134 case ID_WINDOW_TILE_HORZ:
1135 wParam = MDITILE_HORIZONTAL;
1136 // fall through
1137 case ID_WINDOW_TILE_VERT:
1138 ASSERT(MDITILE_VERTICAL == 0);
1139 msg = WM_MDITILE;
1140 break;
1143 ::SendMessage(m_hWndMDIClient, msg, wParam, 0);
1144 return TRUE;
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);
1163 if (pFrame == NULL)
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 ////////////////////////////////////////////////////////////////////////////