winmdi.cpp 32 KB

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