// This is a part of the Microsoft Foundation Classes C++ library. // Copyright (C) 1992-1998 Microsoft Corporation // All rights reserved. // // This source code is only intended as a supplement to the // Microsoft Foundation Classes Reference and related // electronic documentation provided with the library. // See these sources for detailed information regarding the // Microsoft Foundation Classes product. #include "stdafx.h" #include // for DDE execute shell requests #ifdef AFX_CORE4_SEG #pragma code_seg(AFX_CORE4_SEG) #endif #ifdef _DEBUG #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif #define new DEBUG_NEW ///////////////////////////////////////////////////////////////////////////// // CRect for creating windows with the default position/size const AFX_DATADEF CRect CFrameWnd::rectDefault( CW_USEDEFAULT, CW_USEDEFAULT, 0 /* 2*CW_USEDEFAULT */, 0 /* 2*CW_USEDEFAULT */); ///////////////////////////////////////////////////////////////////////////// // CFrameWnd // register for Windows 95 or Windows NT 3.51 AFX_STATIC UINT _afxMsgMouseWheel = (((::GetVersion() & 0x80000000) && LOBYTE(LOWORD(::GetVersion()) == 4)) || (!(::GetVersion() & 0x80000000) && LOBYTE(LOWORD(::GetVersion()) == 3))) ? ::RegisterWindowMessage(MSH_MOUSEWHEEL) : 0; BEGIN_MESSAGE_MAP(CFrameWnd, CWnd) //{{AFX_MSG_MAP(CFrameWnd) ON_WM_INITMENU() ON_WM_INITMENUPOPUP() ON_WM_MENUSELECT() ON_MESSAGE(WM_POPMESSAGESTRING, OnPopMessageString) ON_MESSAGE(WM_SETMESSAGESTRING, OnSetMessageString) ON_MESSAGE(WM_HELPPROMPTADDR, OnHelpPromptAddr) ON_MESSAGE_VOID(WM_IDLEUPDATECMDUI, OnIdleUpdateCmdUI) ON_WM_ENTERIDLE() ON_WM_HSCROLL() ON_WM_VSCROLL() ON_WM_SETFOCUS() ON_WM_CREATE() ON_WM_DESTROY() ON_WM_CLOSE() ON_WM_SIZE() ON_WM_ERASEBKGND() ON_WM_ACTIVATE() ON_WM_NCACTIVATE() ON_WM_SYSCOMMAND() ON_WM_DROPFILES() ON_WM_QUERYENDSESSION() ON_WM_ENDSESSION() ON_WM_SETCURSOR() ON_WM_ENABLE() // OLE palette support ON_WM_QUERYNEWPALETTE() ON_WM_PALETTECHANGED() ON_MESSAGE(WM_COMMANDHELP, OnCommandHelp) ON_MESSAGE(WM_HELPHITTEST, OnHelpHitTest) ON_MESSAGE(WM_ACTIVATETOPLEVEL, OnActivateTopLevel) // turning on and off standard frame gadgetry ON_UPDATE_COMMAND_UI(ID_VIEW_STATUS_BAR, OnUpdateControlBarMenu) ON_COMMAND_EX(ID_VIEW_STATUS_BAR, OnBarCheck) ON_UPDATE_COMMAND_UI(ID_VIEW_TOOLBAR, OnUpdateControlBarMenu) ON_COMMAND_EX(ID_VIEW_TOOLBAR, OnBarCheck) ON_UPDATE_COMMAND_UI(ID_VIEW_REBAR, OnUpdateControlBarMenu) ON_COMMAND_EX(ID_VIEW_REBAR, OnBarCheck) // turning on and off standard mode indicators ON_UPDATE_COMMAND_UI(ID_INDICATOR_CAPS, OnUpdateKeyIndicator) ON_UPDATE_COMMAND_UI(ID_INDICATOR_NUM, OnUpdateKeyIndicator) ON_UPDATE_COMMAND_UI(ID_INDICATOR_SCRL, OnUpdateKeyIndicator) ON_UPDATE_COMMAND_UI(ID_INDICATOR_KANA, OnUpdateKeyIndicator) // standard help handling ON_UPDATE_COMMAND_UI(ID_CONTEXT_HELP, OnUpdateContextHelp) // toolbar "tooltip" notification ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTW, 0, 0xFFFF, OnToolTipText) ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTA, 0, 0xFFFF, OnToolTipText) //}}AFX_MSG_MAP // message handling for standard DDE commands ON_MESSAGE(WM_DDE_INITIATE, OnDDEInitiate) ON_MESSAGE(WM_DDE_EXECUTE, OnDDEExecute) ON_MESSAGE(WM_DDE_TERMINATE, OnDDETerminate) ON_REGISTERED_MESSAGE(_afxMsgMouseWheel, OnRegisteredMouseWheel) END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CFrameWnd construction/destruction CFrameWnd::CFrameWnd() { ASSERT(m_hWnd == NULL); m_nWindow = -1; // unknown window ID m_bAutoMenuEnable = TRUE; // auto enable on by default m_lpfnCloseProc = NULL; m_hMenuDefault = NULL; m_hAccelTable = NULL; m_nIDHelp = 0; m_nIDTracking = 0; m_nIDLastMessage = 0; m_pViewActive = NULL; m_cModalStack = 0; // initialize modality support m_phWndDisable = NULL; m_pNotifyHook = NULL; m_hMenuAlt = NULL; m_nIdleFlags = 0; // no idle work at start m_rectBorder.SetRectEmpty(); m_bHelpMode = HELP_INACTIVE; // not in Shift+F1 help mode m_dwPromptContext = 0; m_pNextFrameWnd = NULL; // not in list yet m_bInRecalcLayout = FALSE; m_pFloatingFrameClass = NULL; m_nShowDelay = -1; // no delay pending AddFrameWnd(); } CFrameWnd::~CFrameWnd() { RemoveFrameWnd(); if (m_phWndDisable != NULL) delete[] (void*)m_phWndDisable; } void CFrameWnd::AddFrameWnd() { // hook it into the CFrameWnd list AFX_MODULE_THREAD_STATE* pState = _AFX_CMDTARGET_GETSTATE()->m_thread; pState->m_frameList.AddHead(this); } void CFrameWnd::RemoveFrameWnd() { // remove this frame window from the list of frame windows AFX_MODULE_THREAD_STATE* pState = _AFX_CMDTARGET_GETSTATE()->m_thread; pState->m_frameList.Remove(this); } ///////////////////////////////////////////////////////////////////////////// // Special processing etc BOOL CFrameWnd::LoadAccelTable(LPCTSTR lpszResourceName) { ASSERT(m_hAccelTable == NULL); // only do once ASSERT(lpszResourceName != NULL); HINSTANCE hInst = AfxFindResourceHandle(lpszResourceName, RT_ACCELERATOR); m_hAccelTable = ::LoadAccelerators(hInst, lpszResourceName); return (m_hAccelTable != NULL); } HACCEL CFrameWnd::GetDefaultAccelerator() { // use document specific accelerator table over m_hAccelTable HACCEL hAccelTable = m_hAccelTable; HACCEL hAccel; CDocument* pDoc = GetActiveDocument(); if (pDoc != NULL && (hAccel = pDoc->GetDefaultAccelerator()) != NULL) hAccelTable = hAccel; return hAccelTable; } BOOL CFrameWnd::PreTranslateMessage(MSG* pMsg) { // check for special cancel modes for combo boxes if (pMsg->message == WM_LBUTTONDOWN || pMsg->message == WM_NCLBUTTONDOWN) AfxCancelModes(pMsg->hwnd); // filter clicks // allow tooltip messages to be filtered if (CWnd::PreTranslateMessage(pMsg)) return TRUE; #ifndef _AFX_NO_OLE_SUPPORT // allow hook to consume message if (m_pNotifyHook != NULL && m_pNotifyHook->OnPreTranslateMessage(pMsg)) return TRUE; #endif if (pMsg->message >= WM_KEYFIRST && pMsg->message <= WM_KEYLAST) { // finally, translate the message HACCEL hAccel = GetDefaultAccelerator(); return hAccel != NULL && ::TranslateAccelerator(m_hWnd, hAccel, pMsg); } return FALSE; } void CFrameWnd::PostNcDestroy() { // default for frame windows is to allocate them on the heap // the default post-cleanup is to 'delete this'. // never explicitly call 'delete' on a CFrameWnd, use DestroyWindow instead delete this; } void CFrameWnd::OnPaletteChanged(CWnd* pFocusWnd) { CWnd::OnPaletteChanged(pFocusWnd); #ifndef _AFX_NO_OLE_SUPPORT if (m_pNotifyHook != NULL) m_pNotifyHook->OnPaletteChanged(pFocusWnd); #endif } BOOL CFrameWnd::OnQueryNewPalette() { #ifndef _AFX_NO_OLE_SUPPORT if (m_pNotifyHook != NULL && m_pNotifyHook->OnQueryNewPalette()) return TRUE; #endif return CWnd::OnQueryNewPalette(); } ///////////////////////////////////////////////////////////////////////////// // CFrameWnd support for context sensitive help. void CFrameWnd::ExitHelpMode() { // if not in help mode currently, this is a no-op if (!m_bHelpMode) return; // only post new WM_EXITHELPMODE message if one doesn't already exist // in the queue. MSG msg; if (!::PeekMessage(&msg, m_hWnd, WM_EXITHELPMODE, WM_EXITHELPMODE, PM_REMOVE|PM_NOYIELD)) { VERIFY(::PostMessage(m_hWnd, WM_EXITHELPMODE, 0, 0)); } // release capture if this window has it if (::GetCapture() == m_hWnd) ReleaseCapture(); CFrameWnd* pFrameWnd = GetTopLevelFrame(); ASSERT_VALID(pFrameWnd); pFrameWnd->m_bHelpMode = m_bHelpMode = HELP_INACTIVE; PostMessage(WM_KICKIDLE); // trigger idle update } BOOL CFrameWnd::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) { CFrameWnd* pFrameWnd = GetTopLevelFrame(); ASSERT_VALID(pFrameWnd); if (pFrameWnd->m_bHelpMode) { SetCursor(afxData.hcurHelp); return TRUE; } return CWnd::OnSetCursor(pWnd, nHitTest, message); } LRESULT CFrameWnd::OnCommandHelp(WPARAM, LPARAM lParam) { if (lParam == 0) { if (IsTracking()) lParam = HID_BASE_COMMAND+m_nIDTracking; else lParam = HID_BASE_RESOURCE+m_nIDHelp; } if (lParam != 0) { CWinApp* pApp = AfxGetApp(); if (pApp != NULL) pApp->WinHelp(lParam); return TRUE; } return FALSE; } LRESULT CFrameWnd::OnHelpHitTest(WPARAM, LPARAM) { if (m_nIDHelp != 0) return HID_BASE_RESOURCE+m_nIDHelp; else return 0; } BOOL CFrameWnd::OnCommand(WPARAM wParam, LPARAM lParam) // return TRUE if command invocation was attempted { HWND hWndCtrl = (HWND)lParam; UINT nID = LOWORD(wParam); CFrameWnd* pFrameWnd = GetTopLevelFrame(); ASSERT_VALID(pFrameWnd); if (pFrameWnd->m_bHelpMode && hWndCtrl == NULL && nID != ID_HELP && nID != ID_DEFAULT_HELP && nID != ID_CONTEXT_HELP) { // route as help if (!SendMessage(WM_COMMANDHELP, 0, HID_BASE_COMMAND+nID)) SendMessage(WM_COMMAND, ID_DEFAULT_HELP); return TRUE; } // route as normal command return CWnd::OnCommand(wParam, lParam); } ///////////////////////////////////////////////////////////////////////////// // CFrameWnd support for modality BOOL AFXAPI AfxIsDescendant(HWND hWndParent, HWND hWndChild) // helper for detecting whether child descendent of parent // (works with owned popups as well) { ASSERT(::IsWindow(hWndParent)); ASSERT(::IsWindow(hWndChild)); do { if (hWndParent == hWndChild) return TRUE; hWndChild = AfxGetParentOwner(hWndChild); } while (hWndChild != NULL); return FALSE; } void CFrameWnd::BeginModalState() { ASSERT(m_hWnd != NULL); ASSERT(::IsWindow(m_hWnd)); // allow stacking, but don't do anything if (++m_cModalStack > 1) return; // determine top-level parent, since that is the true parent of any // modeless windows anyway... CWnd* pParent = GetTopLevelParent(); // first count all windows that need to be disabled UINT nCount = 0; HWND hWnd = ::GetWindow(::GetDesktopWindow(), GW_CHILD); while (hWnd != NULL) { if (::IsWindowEnabled(hWnd) && CWnd::FromHandlePermanent(hWnd) != NULL && AfxIsDescendant(pParent->m_hWnd, hWnd) && ::SendMessage(hWnd, WM_DISABLEMODAL, 0, 0) == 0) { ++nCount; } hWnd = ::GetWindow(hWnd, GW_HWNDNEXT); } if (nCount == 0) return; m_phWndDisable = new HWND[nCount+1]; // disable all windows connected to this frame (and add them to the list) UINT nIndex = 0; hWnd = ::GetWindow(::GetDesktopWindow(), GW_CHILD); while (hWnd != NULL) { if (::IsWindowEnabled(hWnd) && CWnd::FromHandlePermanent(hWnd) != NULL && AfxIsDescendant(pParent->m_hWnd, hWnd) && ::SendMessage(hWnd, WM_DISABLEMODAL, 0, 0) == 0) { ::EnableWindow(hWnd, FALSE); ASSERT(nIndex < nCount); m_phWndDisable[nIndex] = hWnd; ++nIndex; } hWnd = ::GetWindow(hWnd, GW_HWNDNEXT); } // terminate the list with a NULL ASSERT(nIndex < nCount+1); m_phWndDisable[nIndex] = NULL; } void CFrameWnd::EndModalState() { // pop one off the stack (don't undo modalness unless stack is down to zero) if (m_cModalStack == 0 || --m_cModalStack > 0 || m_phWndDisable == NULL) return; // enable all the windows disabled by BeginModalState ASSERT(m_phWndDisable != NULL); UINT nIndex = 0; while (m_phWndDisable[nIndex] != NULL) { ASSERT(m_phWndDisable[nIndex] != NULL); if (::IsWindow(m_phWndDisable[nIndex])) ::EnableWindow(m_phWndDisable[nIndex], TRUE); ++nIndex; } delete[] (void*)m_phWndDisable; m_phWndDisable = NULL; } void CFrameWnd::ShowOwnedWindows(BOOL bShow) { // walk through all top-level windows HWND hWnd = ::GetWindow(::GetDesktopWindow(), GW_CHILD); while (hWnd != NULL) { CWnd* pWnd = CWnd::FromHandlePermanent(hWnd); if (pWnd != NULL && m_hWnd != hWnd && AfxIsDescendant(m_hWnd, hWnd)) { DWORD dwStyle = ::GetWindowLong(hWnd, GWL_STYLE); if (!bShow && (dwStyle & (WS_VISIBLE|WS_DISABLED)) == WS_VISIBLE) { ::ShowWindow(hWnd, SW_HIDE); pWnd->m_nFlags |= WF_TEMPHIDE; } else if (bShow && (dwStyle & (WS_VISIBLE|WS_DISABLED)) == 0 && (pWnd->m_nFlags & WF_TEMPHIDE)) { ::ShowWindow(hWnd, SW_SHOWNOACTIVATE); pWnd->m_nFlags &= ~WF_TEMPHIDE; } } hWnd = ::GetWindow(hWnd, GW_HWNDNEXT); } } void CFrameWnd::OnEnable(BOOL bEnable) { if (bEnable && (m_nFlags & WF_STAYDISABLED)) { // Work around for MAPI support. This makes sure the main window // remains disabled even when the mail system is booting. EnableWindow(FALSE); ::SetFocus(NULL); return; } // only for top-level (and non-owned) windows if (GetParent() != NULL) return; // this causes modal dialogs to be "truly modal" if (!bEnable && !InModalState()) { ASSERT((m_nFlags & WF_MODALDISABLE) == 0); m_nFlags |= WF_MODALDISABLE; BeginModalState(); } else if (bEnable && (m_nFlags & WF_MODALDISABLE)) { m_nFlags &= ~WF_MODALDISABLE; EndModalState(); // cause normal focus logic to kick in if (::GetActiveWindow() == m_hWnd) SendMessage(WM_ACTIVATE, WA_ACTIVE); } // force WM_NCACTIVATE because Windows may think it is unecessary if (bEnable && (m_nFlags & WF_STAYACTIVE)) SendMessage(WM_NCACTIVATE, TRUE); // force WM_NCACTIVATE for floating windows too NotifyFloatingWindows(bEnable ? FS_ENABLE : FS_DISABLE); } void CFrameWnd::NotifyFloatingWindows(DWORD dwFlags) { ASSERT_VALID(this); ASSERT(m_hWnd != NULL); // get top level parent frame window first unless this is a child window CFrameWnd* pParent = (GetStyle() & WS_CHILD) ? this : GetTopLevelFrame(); ASSERT(pParent != NULL); if (dwFlags & (FS_DEACTIVATE|FS_ACTIVATE)) { // update parent window activation state BOOL bActivate = !(dwFlags & FS_DEACTIVATE); BOOL bEnabled = pParent->IsWindowEnabled(); if (bActivate && bEnabled && pParent != this) { // Excel will try to Activate itself when it receives a // WM_NCACTIVATE so we need to keep it from doing that here. m_nFlags |= WF_KEEPMINIACTIVE; pParent->SendMessage(WM_NCACTIVATE, TRUE); m_nFlags &= ~WF_KEEPMINIACTIVE; } else { pParent->SendMessage(WM_NCACTIVATE, FALSE); } } // then update the state of all floating windows owned by the parent HWND hWnd = ::GetWindow(::GetDesktopWindow(), GW_CHILD); while (hWnd != NULL) { if (AfxIsDescendant(pParent->m_hWnd, hWnd)) ::SendMessage(hWnd, WM_FLOATSTATUS, dwFlags, 0); hWnd = ::GetWindow(hWnd, GW_HWNDNEXT); } } ///////////////////////////////////////////////////////////////////////////// // CFrameWnd second phase creation BOOL CFrameWnd::PreCreateWindow(CREATESTRUCT& cs) { if (cs.lpszClass == NULL) { VERIFY(AfxDeferRegisterClass(AFX_WNDFRAMEORVIEW_REG)); cs.lpszClass = _afxWndFrameOrView; // COLOR_WINDOW background } if ((cs.style & FWS_ADDTOTITLE) && afxData.bWin4) cs.style |= FWS_PREFIXTITLE; if (afxData.bWin4) cs.dwExStyle |= WS_EX_CLIENTEDGE; return TRUE; } BOOL CFrameWnd::Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, LPCTSTR lpszMenuName, DWORD dwExStyle, CCreateContext* pContext) { HMENU hMenu = NULL; if (lpszMenuName != NULL) { // load in a menu that will get destroyed when window gets destroyed HINSTANCE hInst = AfxFindResourceHandle(lpszMenuName, RT_MENU); if ((hMenu = ::LoadMenu(hInst, lpszMenuName)) == NULL) { TRACE0("Warning: failed to load menu for CFrameWnd.\n"); PostNcDestroy(); // perhaps delete the C++ object return FALSE; } } m_strTitle = lpszWindowName; // save title for later if (!CreateEx(dwExStyle, lpszClassName, lpszWindowName, dwStyle, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, pParentWnd->GetSafeHwnd(), hMenu, (LPVOID)pContext)) { TRACE0("Warning: failed to create CFrameWnd.\n"); if (hMenu != NULL) DestroyMenu(hMenu); return FALSE; } return TRUE; } CWnd* CFrameWnd::CreateView(CCreateContext* pContext, UINT nID) { ASSERT(m_hWnd != NULL); ASSERT(::IsWindow(m_hWnd)); ASSERT(pContext != NULL); ASSERT(pContext->m_pNewViewClass != NULL); // Note: can be a CWnd with PostNcDestroy self cleanup CWnd* pView = (CWnd*)pContext->m_pNewViewClass->CreateObject(); if (pView == NULL) { TRACE1("Warning: Dynamic create of view type %hs failed.\n", pContext->m_pNewViewClass->m_lpszClassName); return NULL; } ASSERT_KINDOF(CWnd, pView); // views are always created with a border! if (!pView->Create(NULL, NULL, AFX_WS_DEFAULT_VIEW, CRect(0,0,0,0), this, nID, pContext)) { TRACE0("Warning: could not create view for frame.\n"); return NULL; // can't continue without a view } if (afxData.bWin4 && (pView->GetExStyle() & WS_EX_CLIENTEDGE)) { // remove the 3d style from the frame, since the view is // providing it. // make sure to recalc the non-client area ModifyStyleEx(WS_EX_CLIENTEDGE, 0, SWP_FRAMECHANGED); } return pView; } BOOL CFrameWnd::OnCreateClient(LPCREATESTRUCT, CCreateContext* pContext) { // default create client will create a view if asked for it if (pContext != NULL && pContext->m_pNewViewClass != NULL) { if (CreateView(pContext, AFX_IDW_PANE_FIRST) == NULL) return FALSE; } return TRUE; } int CFrameWnd::OnCreate(LPCREATESTRUCT lpcs) { CCreateContext* pContext = (CCreateContext*)lpcs->lpCreateParams; return OnCreateHelper(lpcs, pContext); } int CFrameWnd::OnCreateHelper(LPCREATESTRUCT lpcs, CCreateContext* pContext) { if (CWnd::OnCreate(lpcs) == -1) return -1; // create special children first if (!OnCreateClient(lpcs, pContext)) { TRACE0("Failed to create client pane/view for frame.\n"); return -1; } // post message for initial message string PostMessage(WM_SETMESSAGESTRING, AFX_IDS_IDLEMESSAGE); // make sure the child windows have been properly sized RecalcLayout(); return 0; // create ok } LPCTSTR CFrameWnd::GetIconWndClass(DWORD dwDefaultStyle, UINT nIDResource) { ASSERT_VALID_IDR(nIDResource); HINSTANCE hInst = AfxFindResourceHandle( MAKEINTRESOURCE(nIDResource), RT_GROUP_ICON); HICON hIcon = ::LoadIcon(hInst, MAKEINTRESOURCE(nIDResource)); if (hIcon != NULL) { CREATESTRUCT cs; memset(&cs, 0, sizeof(CREATESTRUCT)); cs.style = dwDefaultStyle; PreCreateWindow(cs); // will fill lpszClassName with default WNDCLASS name // ignore instance handle from PreCreateWindow. WNDCLASS wndcls; if (cs.lpszClass != NULL && GetClassInfo(AfxGetInstanceHandle(), cs.lpszClass, &wndcls) && wndcls.hIcon != hIcon) { // register a very similar WNDCLASS return AfxRegisterWndClass(wndcls.style, wndcls.hCursor, wndcls.hbrBackground, hIcon); } } return NULL; // just use the default } BOOL CFrameWnd::LoadFrame(UINT nIDResource, DWORD dwDefaultStyle, CWnd* pParentWnd, CCreateContext* pContext) { // only do this once ASSERT_VALID_IDR(nIDResource); ASSERT(m_nIDHelp == 0 || m_nIDHelp == nIDResource); m_nIDHelp = nIDResource; // ID for help context (+HID_BASE_RESOURCE) CString strFullString; if (strFullString.LoadString(nIDResource)) AfxExtractSubString(m_strTitle, strFullString, 0); // first sub-string VERIFY(AfxDeferRegisterClass(AFX_WNDFRAMEORVIEW_REG)); // attempt to create the window LPCTSTR lpszClass = GetIconWndClass(dwDefaultStyle, nIDResource); LPCTSTR lpszTitle = m_strTitle; if (!Create(lpszClass, lpszTitle, dwDefaultStyle, rectDefault, pParentWnd, MAKEINTRESOURCE(nIDResource), 0L, pContext)) { return FALSE; // will self destruct on failure normally } // save the default menu handle ASSERT(m_hWnd != NULL); m_hMenuDefault = ::GetMenu(m_hWnd); // load accelerator resource LoadAccelTable(MAKEINTRESOURCE(nIDResource)); if (pContext == NULL) // send initial update SendMessageToDescendants(WM_INITIALUPDATE, 0, 0, TRUE, TRUE); return TRUE; } void CFrameWnd::OnUpdateFrameMenu(HMENU hMenuAlt) { if (hMenuAlt == NULL) { // attempt to get default menu from document CDocument* pDoc = GetActiveDocument(); if (pDoc != NULL) hMenuAlt = pDoc->GetDefaultMenu(); // use default menu stored in frame if none from document if (hMenuAlt == NULL) hMenuAlt = m_hMenuDefault; } // finally, set the menu ::SetMenu(m_hWnd, hMenuAlt); } void CFrameWnd::InitialUpdateFrame(CDocument* pDoc, BOOL bMakeVisible) { // if the frame does not have an active view, set to first pane CView* pView = NULL; if (GetActiveView() == NULL) { CWnd* pWnd = GetDescendantWindow(AFX_IDW_PANE_FIRST, TRUE); if (pWnd != NULL && pWnd->IsKindOf(RUNTIME_CLASS(CView))) { pView = (CView*)pWnd; SetActiveView(pView, FALSE); } } if (bMakeVisible) { // send initial update to all views (and other controls) in the frame SendMessageToDescendants(WM_INITIALUPDATE, 0, 0, TRUE, TRUE); // give view a chance to save the focus (CFormView needs this) if (pView != NULL) pView->OnActivateFrame(WA_INACTIVE, this); // finally, activate the frame // (send the default show command unless the main desktop window) int nCmdShow = -1; // default CWinApp* pApp = AfxGetApp(); if (pApp != NULL && pApp->m_pMainWnd == this) { nCmdShow = pApp->m_nCmdShow; // use the parameter from WinMain pApp->m_nCmdShow = -1; // set to default after first time } ActivateFrame(nCmdShow); if (pView != NULL) pView->OnActivateView(TRUE, pView, pView); } // update frame counts and frame title (may already have been visible) if (pDoc != NULL) pDoc->UpdateFrameCounts(); OnUpdateFrameTitle(TRUE); } ///////////////////////////////////////////////////////////////////////////// // CFrameWnd closing down void CFrameWnd::OnClose() { if (m_lpfnCloseProc != NULL && !(*m_lpfnCloseProc)(this)) return; // Note: only queries the active document CDocument* pDocument = GetActiveDocument(); if (pDocument != NULL && !pDocument->CanCloseFrame(this)) { // document can't close right now -- don't close it return; } CWinApp* pApp = AfxGetApp(); if (pApp != NULL && pApp->m_pMainWnd == this) { // attempt to save all documents if (pDocument == NULL && !pApp->SaveAllModified()) return; // don't close it // hide the application's windows before closing all the documents pApp->HideApplication(); // close all documents first pApp->CloseAllDocuments(FALSE); // don't exit if there are outstanding component objects if (!AfxOleCanExitApp()) { // take user out of control of the app AfxOleSetUserCtrl(FALSE); // don't destroy the main window and close down just yet // (there are outstanding component (OLE) objects) return; } // there are cases where destroying the documents may destroy the // main window of the application. if (!afxContextIsDLL && pApp->m_pMainWnd == NULL) { AfxPostQuitMessage(0); return; } } // detect the case that this is the last frame on the document and // shut down with OnCloseDocument instead. if (pDocument != NULL && pDocument->m_bAutoDelete) { BOOL bOtherFrame = FALSE; POSITION pos = pDocument->GetFirstViewPosition(); while (pos != NULL) { CView* pView = pDocument->GetNextView(pos); ASSERT_VALID(pView); if (pView->GetParentFrame() != this) { bOtherFrame = TRUE; break; } } if (!bOtherFrame) { pDocument->OnCloseDocument(); return; } // allow the document to cleanup before the window is destroyed pDocument->PreCloseFrame(this); } // then destroy the window DestroyWindow(); } void CFrameWnd::OnDestroy() { DestroyDockBars(); // reset menu to default before final shutdown if (m_hMenuDefault != NULL && ::GetMenu(m_hWnd) != m_hMenuDefault) { ::SetMenu(m_hWnd, m_hMenuDefault); ASSERT(::GetMenu(m_hWnd) == m_hMenuDefault); } // Automatically quit when the main window is destroyed. CWinApp* pApp = AfxGetApp(); if (pApp != NULL && pApp->m_pMainWnd == this) { // closing the main application window ::WinHelp(m_hWnd, NULL, HELP_QUIT, 0L); // will call PostQuitMessage in CWnd::OnNcDestroy } CWnd::OnDestroy(); } void CFrameWnd::RemoveControlBar(CControlBar *pBar) { POSITION pos = m_listControlBars.Find(pBar); if (pos != NULL) m_listControlBars.RemoveAt(pos); } ///////////////////////////////////////////////////////////////////////////// // CFrameWnd command/message routing BOOL CFrameWnd::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo) { CPushRoutingFrame push(this); // pump through current view FIRST CView* pView = GetActiveView(); if (pView != NULL && pView->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo)) return TRUE; // then pump through frame if (CWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo)) return TRUE; // last but not least, pump through app CWinApp* pApp = AfxGetApp(); if (pApp != NULL && pApp->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo)) return TRUE; return FALSE; } // Delegate scroll messages to active view as well void CFrameWnd::OnHScroll(UINT, UINT, CScrollBar*) { CWnd* pActiveView = GetActiveView(); if (pActiveView != NULL) { const MSG* pMsg = GetCurrentMessage(); pActiveView->SendMessage(WM_HSCROLL, pMsg->wParam, pMsg->lParam); } } void CFrameWnd::OnVScroll(UINT, UINT, CScrollBar*) { CWnd* pActiveView = GetActiveView(); if (pActiveView != NULL) { const MSG* pMsg = GetCurrentMessage(); pActiveView->SendMessage(WM_VSCROLL, pMsg->wParam, pMsg->lParam); } } LRESULT CFrameWnd::OnActivateTopLevel(WPARAM wParam, LPARAM lParam) { CWnd::OnActivateTopLevel(wParam, lParam); // exit Shift+F1 help mode on activation changes ExitHelpMode(); #ifndef _AFX_NO_OLE_SUPPORT // allow OnFrameWindowActivate to be sent to in-place items if (m_pNotifyHook != NULL) { // activate when active and when not minimized m_pNotifyHook->OnActivate( LOWORD(wParam) != WA_INACTIVE && !HIWORD(wParam)); } #endif // deactivate current active view if (AfxGetThread()->m_pMainWnd == this) { CView* pActiveView = GetActiveView(); if (pActiveView == NULL) pActiveView = GetActiveFrame()->GetActiveView(); if (pActiveView != NULL) pActiveView->OnActivateView(FALSE, pActiveView, pActiveView); } // force idle processing to update any key state indicators PostMessage(WM_KICKIDLE); return 0; } void CFrameWnd::OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized) { CWnd::OnActivate(nState, pWndOther, bMinimized); // get top level frame unless this is a child window // determine if window should be active or not CFrameWnd* pTopLevel = (GetStyle() & WS_CHILD) ? this : GetTopLevelFrame(); ASSERT(pTopLevel != NULL); CWnd* pActive = (nState == WA_INACTIVE ? pWndOther : this); BOOL bStayActive = (pTopLevel == pActive || (pTopLevel == pActive->GetTopLevelFrame() && (pActive == pTopLevel || pActive->SendMessage(WM_FLOATSTATUS, FS_SYNCACTIVE) != 0))); pTopLevel->m_nFlags &= ~WF_STAYACTIVE; if (bStayActive) pTopLevel->m_nFlags |= WF_STAYACTIVE; // sync floating windows to the new state NotifyFloatingWindows(bStayActive ? FS_ACTIVATE : FS_DEACTIVATE); // get active view (use active frame if no active view) CView* pActiveView = GetActiveView(); if (pActiveView == NULL) pActiveView = GetActiveFrame()->GetActiveView(); // when frame gets activated, re-activate current view if (pActiveView != NULL) { if (nState != WA_INACTIVE && !bMinimized) pActiveView->OnActivateView(TRUE, pActiveView, pActiveView); // always notify the view of frame activations pActiveView->OnActivateFrame(nState, this); } } BOOL CFrameWnd::OnNcActivate(BOOL bActive) { // stay active if WF_STAYACTIVE bit is on if (m_nFlags & WF_STAYACTIVE) bActive = TRUE; // but do not stay active if the window is disabled if (!IsWindowEnabled()) bActive = FALSE; // do not call the base class because it will call Default() // and we may have changed bActive. return (BOOL)DefWindowProc(WM_NCACTIVATE, bActive, 0L); } void CFrameWnd::OnSysCommand(UINT nID, LONG lParam) { CFrameWnd* pFrameWnd = GetTopLevelFrame(); ASSERT_VALID(pFrameWnd); // set status bar as appropriate UINT nItemID = (nID & 0xFFF0); // don't interfere with system commands if not in help mode if (pFrameWnd->m_bHelpMode) { switch (nItemID) { case SC_SIZE: case SC_MOVE: case SC_MINIMIZE: case SC_MAXIMIZE: case SC_NEXTWINDOW: case SC_PREVWINDOW: case SC_CLOSE: case SC_RESTORE: case SC_TASKLIST: if (!SendMessage(WM_COMMANDHELP, 0, HID_BASE_COMMAND+ID_COMMAND_FROM_SC(nItemID))) SendMessage(WM_COMMAND, ID_DEFAULT_HELP); return; } } // call default functionality CWnd::OnSysCommand(nID, lParam); } ///////////////////////////////////////////////////////////////////////////// // default frame processing // default drop processing will attempt to open the file void CFrameWnd::OnDropFiles(HDROP hDropInfo) { SetActiveWindow(); // activate us first ! UINT nFiles = ::DragQueryFile(hDropInfo, (UINT)-1, NULL, 0); CWinApp* pApp = AfxGetApp(); ASSERT(pApp != NULL); for (UINT iFile = 0; iFile < nFiles; iFile++) { TCHAR szFileName[_MAX_PATH]; ::DragQueryFile(hDropInfo, iFile, szFileName, _MAX_PATH); pApp->OpenDocumentFile(szFileName); } ::DragFinish(hDropInfo); } // query end session for main frame will attempt to close it all down BOOL CFrameWnd::OnQueryEndSession() { CWinApp* pApp = AfxGetApp(); if (pApp != NULL && pApp->m_pMainWnd == this) return pApp->SaveAllModified(); return TRUE; } // when Windows session ends, close all documents void CFrameWnd::OnEndSession(BOOL bEnding) { if (!bEnding) return; CWinApp* pApp = AfxGetApp(); if (pApp != NULL && pApp->m_pMainWnd == this) { AfxOleSetUserCtrl(TRUE); // keeps from randomly shutting down pApp->CloseAllDocuments(TRUE); // allow application to save settings, etc. pApp->ExitInstance(); } } ///////////////////////////////////////////////////////////////////////////// // Support for Shell DDE Execute messages LRESULT CFrameWnd::OnDDEInitiate(WPARAM wParam, LPARAM lParam) { CWinApp* pApp = AfxGetApp(); if (pApp != NULL && LOWORD(lParam) != 0 && HIWORD(lParam) != 0 && (ATOM)LOWORD(lParam) == pApp->m_atomApp && (ATOM)HIWORD(lParam) == pApp->m_atomSystemTopic) { // make duplicates of the incoming atoms (really adding a reference) TCHAR szAtomName[_MAX_PATH]; VERIFY(GlobalGetAtomName(pApp->m_atomApp, szAtomName, _MAX_PATH - 1) != 0); VERIFY(GlobalAddAtom(szAtomName) == pApp->m_atomApp); VERIFY(GlobalGetAtomName(pApp->m_atomSystemTopic, szAtomName, _MAX_PATH - 1) != 0); VERIFY(GlobalAddAtom(szAtomName) == pApp->m_atomSystemTopic); // send the WM_DDE_ACK (caller will delete duplicate atoms) ::SendMessage((HWND)wParam, WM_DDE_ACK, (WPARAM)m_hWnd, MAKELPARAM(pApp->m_atomApp, pApp->m_atomSystemTopic)); } return 0L; } // always ACK the execute command - even if we do nothing LRESULT CFrameWnd::OnDDEExecute(WPARAM wParam, LPARAM lParam) { // unpack the DDE message UINT unused; HGLOBAL hData; VERIFY(UnpackDDElParam(WM_DDE_EXECUTE, lParam, &unused, (UINT*)&hData)); // get the command string TCHAR szCommand[_MAX_PATH * 2]; LPCTSTR lpsz = (LPCTSTR)GlobalLock(hData); lstrcpyn(szCommand, lpsz, _countof(szCommand)); GlobalUnlock(hData); // acknowledge now - before attempting to execute ::PostMessage((HWND)wParam, WM_DDE_ACK, (WPARAM)m_hWnd, ReuseDDElParam(lParam, WM_DDE_EXECUTE, WM_DDE_ACK, (UINT)0x8000, (UINT)hData)); // don't execute the command when the window is disabled if (!IsWindowEnabled()) { TRACE1("Warning: DDE command '%s' ignored because window is disabled.\n", szCommand); return 0; } // execute the command if (!AfxGetApp()->OnDDECommand(szCommand)) TRACE1("Error: failed to execute DDE command '%s'.\n", szCommand); return 0L; } LRESULT CFrameWnd::OnDDETerminate(WPARAM wParam, LPARAM lParam) { ::PostMessage((HWND)wParam, WM_DDE_TERMINATE, (WPARAM)m_hWnd, lParam); return 0L; } ///////////////////////////////////////////////////////////////////////////// // CFrameWnd attributes CView* CFrameWnd::GetActiveView() const { ASSERT(m_pViewActive == NULL || m_pViewActive->IsKindOf(RUNTIME_CLASS(CView))); return m_pViewActive; } void CFrameWnd::SetActiveView(CView* pViewNew, BOOL bNotify) { #ifdef _DEBUG if (pViewNew != NULL) { ASSERT(IsChild(pViewNew)); ASSERT_KINDOF(CView, pViewNew); } #endif //_DEBUG CView* pViewOld = m_pViewActive; if (pViewNew == pViewOld) return; // do not re-activate if SetActiveView called more than once m_pViewActive = NULL; // no active for the following processing // deactivate the old one if (pViewOld != NULL) pViewOld->OnActivateView(FALSE, pViewNew, pViewOld); // if the OnActivateView moves the active window, // that will veto this change if (m_pViewActive != NULL) return; // already set m_pViewActive = pViewNew; // activate if (pViewNew != NULL && bNotify) pViewNew->OnActivateView(TRUE, pViewNew, pViewOld); } ///////////////////////////////////////////////////////////////////////////// // Special view swapping/activation void CFrameWnd::OnSetFocus(CWnd* pOldWnd) { if (m_pViewActive != NULL) m_pViewActive->SetFocus(); else CWnd::OnSetFocus(pOldWnd); } CDocument* CFrameWnd::GetActiveDocument() { ASSERT_VALID(this); CView* pView = GetActiveView(); if (pView != NULL) return pView->GetDocument(); return NULL; } void CFrameWnd::ShowControlBar(CControlBar* pBar, BOOL bShow, BOOL bDelay) { ASSERT(pBar != NULL); CFrameWnd* pParentFrame = pBar->GetDockingFrame(); ASSERT(pParentFrame->GetTopLevelParent() == GetTopLevelParent()); // parent frame of bar must be related if (bDelay) { pBar->DelayShow(bShow); pParentFrame->DelayRecalcLayout(); } else { pBar->SetWindowPos(NULL, 0, 0, 0, 0, SWP_NOZORDER|SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE| (bShow ? SWP_SHOWWINDOW : SWP_HIDEWINDOW)); // call DelayShow to clear any contradictory DelayShow pBar->DelayShow(bShow); if (bShow || !pBar->IsFloating()) pParentFrame->RecalcLayout(FALSE); } // show or hide the floating frame as appropriate if (pBar->IsFloating()) { int nVisCount = pBar->m_pDockBar != NULL ? pBar->m_pDockBar->GetDockedVisibleCount() : bShow ? 1 : 0; if (nVisCount == 1 && bShow) { pParentFrame->m_nShowDelay = -1; if (bDelay) { pParentFrame->m_nShowDelay = SW_SHOWNA; pParentFrame->RecalcLayout(FALSE); } else pParentFrame->ShowWindow(SW_SHOWNA); } else if (nVisCount == 0) { ASSERT(!bShow); pParentFrame->m_nShowDelay = -1; if (bDelay) pParentFrame->m_nShowDelay = SW_HIDE; else pParentFrame->ShowWindow(SW_HIDE); } else if (!bDelay) { pParentFrame->RecalcLayout(FALSE); } } } ///////////////////////////////////////////////////////////////////////////// // Command prompts void CFrameWnd::OnInitMenu(CMenu* pMenu) { #ifndef _AFX_NO_OLE_SUPPORT // allow hook to consume message if (m_pNotifyHook != NULL) { #ifdef _AFXDLL ASSERT(m_pModuleState != NULL); if (m_pModuleState->m_dwVersion >= 0x423) #endif m_pNotifyHook->OnInitMenu(pMenu); #endif } Default(); } void CFrameWnd::OnInitMenuPopup(CMenu* pMenu, UINT nIndex, BOOL bSysMenu) { AfxCancelModes(m_hWnd); if (bSysMenu) return; // don't support system menu #ifndef _AFX_NO_OLE_SUPPORT // allow hook to consume message if (m_pNotifyHook != NULL) { #ifdef _AFXDLL ASSERT(m_pModuleState != NULL); if (m_pModuleState->m_dwVersion >= 0x423) #endif if (m_pNotifyHook->OnInitMenuPopup(pMenu, nIndex, bSysMenu)) return; } #endif ASSERT(pMenu != NULL); // check the enabled state of various menu items CCmdUI state; state.m_pMenu = pMenu; ASSERT(state.m_pOther == NULL); ASSERT(state.m_pParentMenu == NULL); // determine if menu is popup in top-level menu and set m_pOther to // it if so (m_pParentMenu == NULL indicates that it is secondary popup) HMENU hParentMenu; if (AfxGetThreadState()->m_hTrackingMenu == pMenu->m_hMenu) state.m_pParentMenu = pMenu; // parent == child for tracking popup else if ((hParentMenu = ::GetMenu(m_hWnd)) != NULL) { CWnd* pParent = GetTopLevelParent(); // child windows don't have menus -- need to go to the top! if (pParent != NULL && (hParentMenu = ::GetMenu(pParent->m_hWnd)) != NULL) { int nIndexMax = ::GetMenuItemCount(hParentMenu); for (int nIndex = 0; nIndex < nIndexMax; nIndex++) { if (::GetSubMenu(hParentMenu, nIndex) == pMenu->m_hMenu) { // when popup is found, m_pParentMenu is containing menu state.m_pParentMenu = CMenu::FromHandle(hParentMenu); break; } } } } state.m_nIndexMax = pMenu->GetMenuItemCount(); for (state.m_nIndex = 0; state.m_nIndex < state.m_nIndexMax; state.m_nIndex++) { state.m_nID = pMenu->GetMenuItemID(state.m_nIndex); if (state.m_nID == 0) continue; // menu separator or invalid cmd - ignore it ASSERT(state.m_pOther == NULL); ASSERT(state.m_pMenu != NULL); if (state.m_nID == (UINT)-1) { // possibly a popup menu, route to first item of that popup state.m_pSubMenu = pMenu->GetSubMenu(state.m_nIndex); if (state.m_pSubMenu == NULL || (state.m_nID = state.m_pSubMenu->GetMenuItemID(0)) == 0 || state.m_nID == (UINT)-1) { continue; // first item of popup can't be routed to } state.DoUpdate(this, FALSE); // popups are never auto disabled } else { // normal menu item // Auto enable/disable if frame window has 'm_bAutoMenuEnable' // set and command is _not_ a system command. state.m_pSubMenu = NULL; state.DoUpdate(this, m_bAutoMenuEnable && state.m_nID < 0xF000); } // adjust for menu deletions and additions UINT nCount = pMenu->GetMenuItemCount(); if (nCount < state.m_nIndexMax) { state.m_nIndex -= (state.m_nIndexMax - nCount); while (state.m_nIndex < nCount && pMenu->GetMenuItemID(state.m_nIndex) == state.m_nID) { state.m_nIndex++; } } state.m_nIndexMax = nCount; } } void CFrameWnd::OnMenuSelect(UINT nItemID, UINT nFlags, HMENU hSysMenu) { CFrameWnd* pFrameWnd = GetTopLevelFrame(); ASSERT_VALID(pFrameWnd); #ifndef _AFX_NO_OLE_SUPPORT // allow hook to consume message if (m_pNotifyHook != NULL) { #ifdef _AFXDLL ASSERT(m_pModuleState != NULL); if (m_pModuleState->m_dwVersion >= 0x423) #endif if (m_pNotifyHook->OnMenuSelect(nItemID, nFlags, hSysMenu)) return; } #endif // set the tracking state (update on idle) if (nFlags == 0xFFFF) { // cancel menu operation (go back to idle now) m_nFlags &= ~WF_NOPOPMSG; if (!pFrameWnd->m_bHelpMode) m_nIDTracking = AFX_IDS_IDLEMESSAGE; else m_nIDTracking = AFX_IDS_HELPMODEMESSAGE; SendMessage(WM_SETMESSAGESTRING, (WPARAM)m_nIDTracking); ASSERT(m_nIDTracking == m_nIDLastMessage); // update right away CWnd* pWnd = GetMessageBar(); if (pWnd != NULL) pWnd->UpdateWindow(); } else { if (nItemID == 0 || nFlags & (MF_SEPARATOR|MF_POPUP)) { // nothing should be displayed m_nIDTracking = 0; } else if (nItemID >= 0xF000 && nItemID < 0xF1F0) // max of 31 SC_s { // special strings table entries for system commands m_nIDTracking = ID_COMMAND_FROM_SC(nItemID); ASSERT(m_nIDTracking >= AFX_IDS_SCFIRST && m_nIDTracking < AFX_IDS_SCFIRST + 31); } else if (nItemID >= AFX_IDM_FIRST_MDICHILD) { // all MDI Child windows map to the same help id m_nIDTracking = AFX_IDS_MDICHILD; } else { // track on idle m_nIDTracking = nItemID; } pFrameWnd->m_nFlags |= WF_NOPOPMSG; } // when running in-place, it is necessary to cause a message to // be pumped through the queue. if (m_nIDTracking != m_nIDLastMessage && GetParent() != NULL) PostMessage(WM_KICKIDLE); } void CFrameWnd::GetMessageString(UINT nID, CString& rMessage) const { // load appropriate string LPTSTR lpsz = rMessage.GetBuffer(255); if (AfxLoadString(nID, lpsz) != 0) { // first newline terminates actual string lpsz = _tcschr(lpsz, '\n'); if (lpsz != NULL) *lpsz = '\0'; } else { // not found TRACE1("Warning: no message line prompt for ID 0x%04X.\n", nID); } rMessage.ReleaseBuffer(); } LRESULT CFrameWnd::OnPopMessageString(WPARAM wParam, LPARAM lParam) { if (m_nFlags & WF_NOPOPMSG) return 0; return SendMessage(WM_SETMESSAGESTRING, wParam, lParam); } LRESULT CFrameWnd::OnSetMessageString(WPARAM wParam, LPARAM lParam) { UINT nIDLast = m_nIDLastMessage; m_nFlags &= ~WF_NOPOPMSG; CWnd* pMessageBar = GetMessageBar(); if (pMessageBar != NULL) { LPCTSTR lpsz = NULL; CString strMessage; // set the message bar text if (lParam != 0) { ASSERT(wParam == 0); // can't have both an ID and a string lpsz = (LPCTSTR)lParam; // set an explicit string } else if (wParam != 0) { // map SC_CLOSE to PREVIEW_CLOSE when in print preview mode if (wParam == AFX_IDS_SCCLOSE && m_lpfnCloseProc != NULL) wParam = AFX_IDS_PREVIEW_CLOSE; // get message associated with the ID indicated by wParam GetMessageString(wParam, strMessage); lpsz = strMessage; } pMessageBar->SetWindowText(lpsz); // update owner of the bar in terms of last message selected CFrameWnd* pFrameWnd = pMessageBar->GetParentFrame(); if (pFrameWnd != NULL) { pFrameWnd->m_nIDLastMessage = (UINT)wParam; pFrameWnd->m_nIDTracking = (UINT)wParam; } } m_nIDLastMessage = (UINT)wParam; // new ID (or 0) m_nIDTracking = (UINT)wParam; // so F1 on toolbar buttons work return nIDLast; } LRESULT CFrameWnd::OnHelpPromptAddr(WPARAM, LPARAM) { return (LRESULT)&m_dwPromptContext; } CWnd* CFrameWnd::GetMessageBar() { return GetDescendantWindow(AFX_IDW_STATUS_BAR, TRUE); } void CFrameWnd::OnEnterIdle(UINT nWhy, CWnd* pWho) { CWnd::OnEnterIdle(nWhy, pWho); if (nWhy != MSGF_MENU || m_nIDTracking == m_nIDLastMessage) return; SetMessageText(m_nIDTracking); ASSERT(m_nIDTracking == m_nIDLastMessage); } void CFrameWnd::SetMessageText(LPCTSTR lpszText) { SendMessage(WM_SETMESSAGESTRING, 0, (LPARAM)lpszText); } void CFrameWnd::SetMessageText(UINT nID) { SendMessage(WM_SETMESSAGESTRING, (WPARAM)nID); } ///////////////////////////////////////////////////////////////////////////// // CFrameWnd standard control bar management void CFrameWnd::DestroyDockBars() { // create a list of all the dock bars // this is necessary because m_listControlBars will change // as the dock bars and floating frames are destroyed CPtrList listDockBars; POSITION pos = m_listControlBars.GetHeadPosition(); while (pos != NULL) { CDockBar* pDockBar = (CDockBar*)m_listControlBars.GetNext(pos); ASSERT(pDockBar != NULL); if (pDockBar->IsDockBar()) listDockBars.AddTail(pDockBar); } pos = listDockBars.GetHeadPosition(); while (pos != NULL) { CDockBar* pDockBar = (CDockBar*)listDockBars.GetNext(pos); if (pDockBar->m_bFloating) { CFrameWnd* pFrameWnd = pDockBar->GetParentFrame(); ASSERT_VALID(pFrameWnd); pFrameWnd->DestroyWindow(); } else pDockBar->DestroyWindow(); } } CControlBar* CFrameWnd::GetControlBar(UINT nID) { if (nID == 0) return NULL; POSITION pos = m_listControlBars.GetHeadPosition(); while (pos != NULL) { CControlBar* pBar = (CControlBar*)m_listControlBars.GetNext(pos); ASSERT(pBar != NULL); if (_AfxGetDlgCtrlID(pBar->m_hWnd) == nID) { ASSERT_KINDOF(CControlBar, pBar); return pBar; } } return NULL; } void CFrameWnd::OnUpdateControlBarMenu(CCmdUI* pCmdUI) { ASSERT(ID_VIEW_STATUS_BAR == AFX_IDW_STATUS_BAR); ASSERT(ID_VIEW_TOOLBAR == AFX_IDW_TOOLBAR); ASSERT(ID_VIEW_REBAR == AFX_IDW_REBAR); CControlBar* pBar = GetControlBar(pCmdUI->m_nID); if (pBar != NULL) { pCmdUI->SetCheck((pBar->GetStyle() & WS_VISIBLE) != 0); return; } pCmdUI->ContinueRouting(); } BOOL CFrameWnd::OnBarCheck(UINT nID) { ASSERT(ID_VIEW_STATUS_BAR == AFX_IDW_STATUS_BAR); ASSERT(ID_VIEW_TOOLBAR == AFX_IDW_TOOLBAR); ASSERT(ID_VIEW_REBAR == AFX_IDW_REBAR); CControlBar* pBar = GetControlBar(nID); if (pBar != NULL) { ShowControlBar(pBar, (pBar->GetStyle() & WS_VISIBLE) == 0, FALSE); return TRUE; } return FALSE; } BOOL CFrameWnd::OnToolTipText(UINT, NMHDR* pNMHDR, LRESULT* pResult) { ASSERT(pNMHDR->code == TTN_NEEDTEXTA || pNMHDR->code == TTN_NEEDTEXTW); // need to handle both ANSI and UNICODE versions of the message TOOLTIPTEXTA* pTTTA = (TOOLTIPTEXTA*)pNMHDR; TOOLTIPTEXTW* pTTTW = (TOOLTIPTEXTW*)pNMHDR; TCHAR szFullText[256]; CString strTipText; UINT nID = pNMHDR->idFrom; if (pNMHDR->code == TTN_NEEDTEXTA && (pTTTA->uFlags & TTF_IDISHWND) || pNMHDR->code == TTN_NEEDTEXTW && (pTTTW->uFlags & TTF_IDISHWND)) { // idFrom is actually the HWND of the tool nID = _AfxGetDlgCtrlID((HWND)nID); } if (nID != 0) // will be zero on a separator { // don't handle the message if no string resource found if (AfxLoadString(nID, szFullText) == 0) return FALSE; // this is the command id, not the button index AfxExtractSubString(strTipText, szFullText, 1, '\n'); } #ifndef _UNICODE if (pNMHDR->code == TTN_NEEDTEXTA) lstrcpyn(pTTTA->szText, strTipText, _countof(pTTTA->szText)); else _mbstowcsz(pTTTW->szText, strTipText, _countof(pTTTW->szText)); #else if (pNMHDR->code == TTN_NEEDTEXTA) _wcstombsz(pTTTA->szText, strTipText, _countof(pTTTA->szText)); else lstrcpyn(pTTTW->szText, strTipText, _countof(pTTTW->szText)); #endif *pResult = 0; // bring the tooltip window above other popup windows ::SetWindowPos(pNMHDR->hwndFrom, HWND_TOP, 0, 0, 0, 0, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOOWNERZORDER); return TRUE; // message was handled } ///////////////////////////////////////////////////////////////////////////// // Support for standard status bar void CFrameWnd::OnUpdateKeyIndicator(CCmdUI* pCmdUI) { UINT nVK; UINT flag = 0x0001; switch (pCmdUI->m_nID) { case ID_INDICATOR_CAPS: nVK = VK_CAPITAL; break; case ID_INDICATOR_NUM: nVK = VK_NUMLOCK; break; case ID_INDICATOR_SCRL: nVK = VK_SCROLL; break; case ID_INDICATOR_KANA: nVK = VK_KANA; // WINBUG: Special case for Windows 3.x. The wrong bit was toggled // in those systems so this must be special cased. This is fixed // on systems whose version is 4.x or greater. if (!afxData.bWin4) flag = 0x8000; break; default: TRACE1("Warning: OnUpdateKeyIndicator - unknown indicator 0x%04X.\n", pCmdUI->m_nID); pCmdUI->ContinueRouting(); return; // not for us } pCmdUI->Enable(::GetKeyState(nVK) & flag); // enable static text based on toggled key state ASSERT(pCmdUI->m_bEnableChanged); } void CFrameWnd::OnUpdateContextHelp(CCmdUI* pCmdUI) { if (AfxGetMainWnd() == this) pCmdUI->SetCheck(!!m_bHelpMode); else pCmdUI->ContinueRouting(); } ///////////////////////////////////////////////////////////////////////////// // Setting title of frame window - UISG standard void CFrameWnd::OnUpdateFrameTitle(BOOL bAddToTitle) { if ((GetStyle() & FWS_ADDTOTITLE) == 0) return; // leave it alone! #ifndef _AFX_NO_OLE_SUPPORT // allow hook to set the title (used for OLE support) if (m_pNotifyHook != NULL && m_pNotifyHook->OnUpdateFrameTitle()) return; #endif CDocument* pDocument = GetActiveDocument(); if (bAddToTitle && pDocument != NULL) UpdateFrameTitleForDocument(pDocument->GetTitle()); else UpdateFrameTitleForDocument(NULL); } void CFrameWnd::UpdateFrameTitleForDocument(LPCTSTR lpszDocName) { // copy first part of title loaded at time of frame creation TCHAR szText[256+_MAX_PATH]; if (GetStyle() & FWS_PREFIXTITLE) { szText[0] = '\0'; // start with nothing // get name of currently active view if (lpszDocName != NULL) { lstrcpy(szText, lpszDocName); // add current window # if needed if (m_nWindow > 0) wsprintf(szText + lstrlen(szText), _T(":%d"), m_nWindow); lstrcat(szText, _T(" - ")); } lstrcat(szText, m_strTitle); } else { // get name of currently active view lstrcpy(szText, m_strTitle); if (lpszDocName != NULL) { lstrcat(szText, _T(" - ")); lstrcat(szText, lpszDocName); // add current window # if needed if (m_nWindow > 0) wsprintf(szText + lstrlen(szText), _T(":%d"), m_nWindow); } } // set title if changed, but don't remove completely // Note: will be excessive for MDI Frame with maximized child AfxSetWindowText(m_hWnd, szText); } ///////////////////////////////////////////////////////////////////////////// void CFrameWnd::OnSetPreviewMode(BOOL bPreview, CPrintPreviewState* pState) { // default implementation changes control bars, menu and main pane window #ifndef _AFX_NO_OLE_SUPPORT CFrameWnd* pActiveFrame = GetActiveFrame(); ASSERT_VALID(pActiveFrame); if (bPreview && pActiveFrame->m_pNotifyHook != NULL) pActiveFrame->m_pNotifyHook->OnDocActivate(FALSE); #endif // Set visibility of standard ControlBars (only the first 32) DWORD dwOldStates = 0; POSITION pos = m_listControlBars.GetHeadPosition(); while (pos != NULL) { CControlBar* pBar = (CControlBar*)m_listControlBars.GetNext(pos); ASSERT_VALID(pBar); UINT nID = _AfxGetDlgCtrlID(pBar->m_hWnd); if (nID >= AFX_IDW_CONTROLBAR_FIRST && nID <= AFX_IDW_CONTROLBAR_FIRST+31) { DWORD dwMask = 1L << (nID - AFX_IDW_CONTROLBAR_FIRST); if (pBar->IsVisible()) dwOldStates |= dwMask; // save if previously visible if (!pBar->IsDockBar() || nID != AFX_IDW_DOCKBAR_FLOAT) ShowControlBar(pBar, (pState->dwStates & dwMask), TRUE); } } pState->dwStates = dwOldStates; // save for restore if (bPreview) { // Entering Print Preview ASSERT(m_lpfnCloseProc == NULL); // no chaining m_lpfnCloseProc = pState->lpfnCloseProc; // show any modeless dialogs, popup windows, float tools, etc ShowOwnedWindows(FALSE); // Hide the main pane HWND hWnd = ::GetDlgItem(m_hWnd, pState->nIDMainPane); ASSERT(hWnd != NULL); // must be one that we are hiding! ::ShowWindow(hWnd, SW_HIDE); // Get rid of the menu first (will resize the window) pState->hMenu = ::GetMenu(m_hWnd); if (pState->hMenu != NULL) { // Invalidate before SetMenu since we are going to replace // the frame's client area anyway Invalidate(); SetMenu(NULL); m_nIdleFlags &= ~idleMenu; // avoid any idle menu processing } // Save the accelerator table and remove it. pState->hAccelTable = m_hAccelTable; m_hAccelTable = NULL; LoadAccelTable(MAKEINTRESOURCE(AFX_IDR_PREVIEW_ACCEL)); // Make room for the PreviewView by changing AFX_IDW_PANE_FIRST's ID // to AFX_IDW_PREVIEW_FIRST if (pState->nIDMainPane != AFX_IDW_PANE_FIRST) hWnd = ::GetDlgItem(m_hWnd, AFX_IDW_PANE_FIRST); if (hWnd != NULL) _AfxSetDlgCtrlID(hWnd, AFX_IDW_PANE_SAVE); #ifdef _DEBUG if ((::GetWindowLong(m_hWnd, GWL_STYLE) & (WS_HSCROLL|WS_VSCROLL)) != 0) TRACE0("Warning: scroll bars in frame windows may cause unusual behaviour.\n"); #endif } else { // Leaving Preview m_lpfnCloseProc = NULL; // shift original AFX_IDW_PANE_FIRST back to its rightful ID HWND hWnd = ::GetDlgItem(m_hWnd, AFX_IDW_PANE_SAVE); if (hWnd != NULL) { HWND hWndTemp = ::GetDlgItem(m_hWnd, AFX_IDW_PANE_FIRST); if (hWndTemp != NULL) _AfxSetDlgCtrlID(hWndTemp, AFX_IDW_PANE_SAVE); _AfxSetDlgCtrlID(hWnd, AFX_IDW_PANE_FIRST); } // put the menu back in place if it was removed before if (pState->hMenu != NULL) { // Invalidate before SetMenu since we are going to replace // the frame's client area anyway Invalidate(); ::SetMenu(m_hWnd, pState->hMenu); } // recalc layout now, before showing the main pane #ifndef _AFX_NO_OLE_SUPPORT if (pActiveFrame->m_pNotifyHook != NULL) pActiveFrame->m_pNotifyHook->OnDocActivate(TRUE); #endif RecalcLayout(); // now show main pane that was hidden if (pState->nIDMainPane != AFX_IDW_PANE_FIRST) hWnd = ::GetDlgItem(m_hWnd, pState->nIDMainPane); ASSERT(hWnd != NULL); ::ShowWindow(hWnd, SW_SHOW); // Restore the Accelerator table m_hAccelTable = pState->hAccelTable; // show any modeless dialogs, popup windows, float tools, etc ShowOwnedWindows(TRUE); } } void CFrameWnd::DelayUpdateFrameMenu(HMENU hMenuAlt) { m_hMenuAlt = hMenuAlt; m_nIdleFlags |= idleMenu; } void CFrameWnd::OnIdleUpdateCmdUI() { // update menu if necessary if (m_nIdleFlags & idleMenu) OnUpdateFrameMenu(m_hMenuAlt); // update title if necessary if (m_nIdleFlags & idleTitle) OnUpdateFrameTitle(TRUE); // recalc layout if necessary if (m_nIdleFlags & idleLayout) { RecalcLayout(m_nIdleFlags & idleNotify); UpdateWindow(); } // set the current message string if necessary if (m_nIDTracking != m_nIDLastMessage) { SetMessageText(m_nIDTracking); ASSERT(m_nIDTracking == m_nIDLastMessage); } m_nIdleFlags = 0; } CFrameWnd* CFrameWnd::GetActiveFrame() { // by default, the active frame is the frame itself (MDI is different) return this; } void CFrameWnd::RecalcLayout(BOOL bNotify) { if (m_bInRecalcLayout) return; m_bInRecalcLayout = TRUE; // clear idle flags for recalc layout if called elsewhere if (m_nIdleFlags & idleNotify) bNotify = TRUE; m_nIdleFlags &= ~(idleLayout|idleNotify); #ifndef _AFX_NO_OLE_SUPPORT // call the layout hook -- OLE support uses this hook if (bNotify && m_pNotifyHook != NULL) m_pNotifyHook->OnRecalcLayout(); #endif // reposition all the child windows (regardless of ID) if (GetStyle() & FWS_SNAPTOBARS) { CRect rect(0, 0, 32767, 32767); RepositionBars(0, 0xffff, AFX_IDW_PANE_FIRST, reposQuery, &rect, &rect, FALSE); RepositionBars(0, 0xffff, AFX_IDW_PANE_FIRST, reposExtra, &m_rectBorder, &rect, TRUE); CalcWindowRect(&rect); SetWindowPos(NULL, 0, 0, rect.Width(), rect.Height(), SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER); } else RepositionBars(0, 0xffff, AFX_IDW_PANE_FIRST, reposExtra, &m_rectBorder); m_bInRecalcLayout = FALSE; } // CFrameWnd implementation of OLE border space negotiation BOOL CFrameWnd::NegotiateBorderSpace(UINT nBorderCmd, LPRECT lpRectBorder) { CRect border, request; switch (nBorderCmd) { case borderGet: ASSERT(lpRectBorder != NULL); RepositionBars(0, 0xffff, AFX_IDW_PANE_FIRST, reposQuery, lpRectBorder); break; case borderRequest: return TRUE; case borderSet: if (lpRectBorder == NULL) { if (!m_rectBorder.IsRectNull()) { // releasing all border space -- recalc needed m_rectBorder.SetRectEmpty(); return TRUE; } // original rect is empty & lpRectBorder is NULL, no recalc needed return FALSE; } if (!::EqualRect(m_rectBorder, lpRectBorder)) { // the rects are different -- recalc needed m_rectBorder.CopyRect(lpRectBorder); return TRUE; } return FALSE; // no recalc needed default: ASSERT(FALSE); // invalid CFrameWnd::BorderCmd } return TRUE; } void CFrameWnd::OnSize(UINT nType, int cx, int cy) { CWnd::OnSize(nType, cx, cy); // important for MDI Children if (nType != SIZE_MINIMIZED) RecalcLayout(); } BOOL CFrameWnd::OnEraseBkgnd(CDC* pDC) { if (m_pViewActive != NULL) return TRUE; // active view will erase/paint itself // for view-less frame just use the default background fill return CWnd::OnEraseBkgnd(pDC); } LRESULT CFrameWnd::OnRegisteredMouseWheel(WPARAM wParam, LPARAM lParam) { // convert from MSH_MOUSEWHEEL to WM_MOUSEWHEEL WORD keyState = 0; keyState |= (::GetKeyState(VK_CONTROL) < 0) ? MK_CONTROL : 0; keyState |= (::GetKeyState(VK_SHIFT) < 0) ? MK_SHIFT : 0; LRESULT lResult; HWND hwFocus = ::GetFocus(); const HWND hwDesktop = ::GetDesktopWindow(); if (hwFocus == NULL) lResult = SendMessage(WM_MOUSEWHEEL, (wParam << 16) | keyState, lParam); else { do { lResult = ::SendMessage(hwFocus, WM_MOUSEWHEEL, (wParam << 16) | keyState, lParam); hwFocus = ::GetParent(hwFocus); } while (lResult == 0 && hwFocus != NULL && hwFocus != hwDesktop); } return lResult; } void CFrameWnd::ActivateFrame(int nCmdShow) // nCmdShow is the normal show mode this frame should be in { // translate default nCmdShow (-1) if (nCmdShow == -1) { if (!IsWindowVisible()) nCmdShow = SW_SHOWNORMAL; else if (IsIconic()) nCmdShow = SW_RESTORE; } // bring to top before showing BringToTop(nCmdShow); if (nCmdShow != -1) { // show the window as specified ShowWindow(nCmdShow); // and finally, bring to top after showing BringToTop(nCmdShow); } } void CFrameWnd::BringToTop(int nCmdShow) { // place the window on top except for certain nCmdShow if (nCmdShow != SW_HIDE && nCmdShow != SW_MINIMIZE && nCmdShow != SW_SHOWMINNOACTIVE && nCmdShow != SW_SHOWNA && nCmdShow != SW_SHOWNOACTIVATE) { // if no last active popup, it will return m_hWnd HWND hWndLastPop = ::GetLastActivePopup(m_hWnd); ::BringWindowToTop(hWndLastPop); } } ///////////////////////////////////////////////////////////////////////////// // CFrameWnd Diagnostics #ifdef _DEBUG void CFrameWnd::AssertValid() const { CWnd::AssertValid(); if (m_pViewActive != NULL) ASSERT_VALID(m_pViewActive); } void CFrameWnd::Dump(CDumpContext& dc) const { CWnd::Dump(dc); dc << "m_hAccelTable = " << (UINT)m_hAccelTable; dc << "\nm_nWindow = " << m_nWindow; dc << "\nm_nIDHelp = " << m_nIDHelp; dc << "\nm_nIDTracking = " << m_nIDTracking; dc << "\nm_nIDLastMessage = " << m_nIDLastMessage; if (m_pViewActive != NULL) dc << "\nwith active view: " << m_pViewActive; else dc << "\nno active view"; dc << "\n"; } #endif //_DEBUG ///////////////////////////////////////////////////////////////////////////// // CControlBar segmentation CFrameWnd* CControlBar::GetDockingFrame() const { CFrameWnd* pFrameWnd = GetParentFrame(); if (pFrameWnd == NULL) pFrameWnd = m_pDockSite; ASSERT(pFrameWnd != NULL); ASSERT_KINDOF(CFrameWnd, pFrameWnd); return pFrameWnd; } BOOL CControlBar::IsFloating() const { if (IsDockBar()) return ((CDockBar*)this)->m_bFloating; else return m_pDockBar != NULL && m_pDockBar->m_bFloating; } #ifdef AFX_INIT_SEG #pragma code_seg(AFX_INIT_SEG) #endif // in this file for IsKindOf library granularity (IsKindOf references these) IMPLEMENT_DYNCREATE(CFrameWnd, CWnd) IMPLEMENT_DYNAMIC(CView, CWnd) IMPLEMENT_DYNAMIC(CControlBar, CWnd) /////////////////////////////////////////////////////////////////////////////