home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / vc98 / mfc / src / winfrm.cpp < prev    next >
C/C++ Source or Header  |  1998-06-16  |  60KB  |  2,173 lines

  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.  
  11. #include "stdafx.h"
  12. #include <dde.h>        // for DDE execute shell requests
  13.  
  14. #ifdef AFX_CORE4_SEG
  15. #pragma code_seg(AFX_CORE4_SEG)
  16. #endif
  17.  
  18. #ifdef _DEBUG
  19. #undef THIS_FILE
  20. static char THIS_FILE[] = __FILE__;
  21. #endif
  22.  
  23. #define new DEBUG_NEW
  24.  
  25. /////////////////////////////////////////////////////////////////////////////
  26. // CRect for creating windows with the default position/size
  27.  
  28. const AFX_DATADEF CRect CFrameWnd::rectDefault(
  29.     CW_USEDEFAULT, CW_USEDEFAULT,
  30.     0 /* 2*CW_USEDEFAULT */, 0 /* 2*CW_USEDEFAULT */);
  31.  
  32. /////////////////////////////////////////////////////////////////////////////
  33. // CFrameWnd
  34.  
  35. // register for Windows 95 or Windows NT 3.51
  36. AFX_STATIC UINT _afxMsgMouseWheel =
  37.    (((::GetVersion() & 0x80000000) && LOBYTE(LOWORD(::GetVersion()) == 4)) ||
  38.      (!(::GetVersion() & 0x80000000) && LOBYTE(LOWORD(::GetVersion()) == 3)))
  39.      ? ::RegisterWindowMessage(MSH_MOUSEWHEEL) : 0;
  40.  
  41. BEGIN_MESSAGE_MAP(CFrameWnd, CWnd)
  42.     //{{AFX_MSG_MAP(CFrameWnd)
  43.     ON_WM_INITMENU()
  44.     ON_WM_INITMENUPOPUP()
  45.     ON_WM_MENUSELECT()
  46.     ON_MESSAGE(WM_POPMESSAGESTRING, OnPopMessageString)
  47.     ON_MESSAGE(WM_SETMESSAGESTRING, OnSetMessageString)
  48.     ON_MESSAGE(WM_HELPPROMPTADDR, OnHelpPromptAddr)
  49.     ON_MESSAGE_VOID(WM_IDLEUPDATECMDUI, OnIdleUpdateCmdUI)
  50.     ON_WM_ENTERIDLE()
  51.     ON_WM_HSCROLL()
  52.     ON_WM_VSCROLL()
  53.     ON_WM_SETFOCUS()
  54.     ON_WM_CREATE()
  55.     ON_WM_DESTROY()
  56.     ON_WM_CLOSE()
  57.     ON_WM_SIZE()
  58.     ON_WM_ERASEBKGND()
  59.     ON_WM_ACTIVATE()
  60.     ON_WM_NCACTIVATE()
  61.     ON_WM_SYSCOMMAND()
  62.     ON_WM_DROPFILES()
  63.     ON_WM_QUERYENDSESSION()
  64.     ON_WM_ENDSESSION()
  65.     ON_WM_SETCURSOR()
  66.     ON_WM_ENABLE()
  67.     // OLE palette support
  68.     ON_WM_QUERYNEWPALETTE()
  69.     ON_WM_PALETTECHANGED()
  70.     ON_MESSAGE(WM_COMMANDHELP, OnCommandHelp)
  71.     ON_MESSAGE(WM_HELPHITTEST, OnHelpHitTest)
  72.     ON_MESSAGE(WM_ACTIVATETOPLEVEL, OnActivateTopLevel)
  73.     // turning on and off standard frame gadgetry
  74.     ON_UPDATE_COMMAND_UI(ID_VIEW_STATUS_BAR, OnUpdateControlBarMenu)
  75.     ON_COMMAND_EX(ID_VIEW_STATUS_BAR, OnBarCheck)
  76.     ON_UPDATE_COMMAND_UI(ID_VIEW_TOOLBAR, OnUpdateControlBarMenu)
  77.     ON_COMMAND_EX(ID_VIEW_TOOLBAR, OnBarCheck)
  78.     ON_UPDATE_COMMAND_UI(ID_VIEW_REBAR, OnUpdateControlBarMenu)
  79.     ON_COMMAND_EX(ID_VIEW_REBAR, OnBarCheck)
  80.     // turning on and off standard mode indicators
  81.     ON_UPDATE_COMMAND_UI(ID_INDICATOR_CAPS, OnUpdateKeyIndicator)
  82.     ON_UPDATE_COMMAND_UI(ID_INDICATOR_NUM, OnUpdateKeyIndicator)
  83.     ON_UPDATE_COMMAND_UI(ID_INDICATOR_SCRL, OnUpdateKeyIndicator)
  84.     ON_UPDATE_COMMAND_UI(ID_INDICATOR_KANA, OnUpdateKeyIndicator)
  85.     // standard help handling
  86.     ON_UPDATE_COMMAND_UI(ID_CONTEXT_HELP, OnUpdateContextHelp)
  87.     // toolbar "tooltip" notification
  88.     ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTW, 0, 0xFFFF, OnToolTipText)
  89.     ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTA, 0, 0xFFFF, OnToolTipText)
  90.     //}}AFX_MSG_MAP
  91.     // message handling for standard DDE commands
  92.     ON_MESSAGE(WM_DDE_INITIATE, OnDDEInitiate)
  93.     ON_MESSAGE(WM_DDE_EXECUTE, OnDDEExecute)
  94.     ON_MESSAGE(WM_DDE_TERMINATE, OnDDETerminate)
  95.     ON_REGISTERED_MESSAGE(_afxMsgMouseWheel, OnRegisteredMouseWheel)
  96. END_MESSAGE_MAP()
  97.  
  98. /////////////////////////////////////////////////////////////////////////////
  99. // CFrameWnd construction/destruction
  100.  
  101. CFrameWnd::CFrameWnd()
  102. {
  103.     ASSERT(m_hWnd == NULL);
  104.  
  105.     m_nWindow = -1;                 // unknown window ID
  106.     m_bAutoMenuEnable = TRUE;       // auto enable on by default
  107.     m_lpfnCloseProc = NULL;
  108.     m_hMenuDefault = NULL;
  109.     m_hAccelTable = NULL;
  110.     m_nIDHelp = 0;
  111.     m_nIDTracking = 0;
  112.     m_nIDLastMessage = 0;
  113.     m_pViewActive = NULL;
  114.  
  115.     m_cModalStack = 0;              // initialize modality support
  116.     m_phWndDisable = NULL;
  117.     m_pNotifyHook = NULL;
  118.     m_hMenuAlt = NULL;
  119.     m_nIdleFlags = 0;               // no idle work at start
  120.     m_rectBorder.SetRectEmpty();
  121.  
  122.     m_bHelpMode = HELP_INACTIVE;    // not in Shift+F1 help mode
  123.     m_dwPromptContext = 0;
  124.  
  125.     m_pNextFrameWnd = NULL;         // not in list yet
  126.  
  127.     m_bInRecalcLayout = FALSE;
  128.     m_pFloatingFrameClass = NULL;
  129.     m_nShowDelay = -1;              // no delay pending
  130.  
  131.     AddFrameWnd();
  132. }
  133.  
  134. CFrameWnd::~CFrameWnd()
  135. {
  136.     RemoveFrameWnd();
  137.     if (m_phWndDisable != NULL)
  138.         delete[] (void*)m_phWndDisable;
  139. }
  140.  
  141. void CFrameWnd::AddFrameWnd()
  142. {
  143.     // hook it into the CFrameWnd list
  144.     AFX_MODULE_THREAD_STATE* pState = _AFX_CMDTARGET_GETSTATE()->m_thread;
  145.     pState->m_frameList.AddHead(this);
  146. }
  147.  
  148. void CFrameWnd::RemoveFrameWnd()
  149. {
  150.     // remove this frame window from the list of frame windows
  151.     AFX_MODULE_THREAD_STATE* pState = _AFX_CMDTARGET_GETSTATE()->m_thread;
  152.     pState->m_frameList.Remove(this);
  153. }
  154.  
  155. /////////////////////////////////////////////////////////////////////////////
  156. // Special processing etc
  157.  
  158. BOOL CFrameWnd::LoadAccelTable(LPCTSTR lpszResourceName)
  159. {
  160.     ASSERT(m_hAccelTable == NULL);  // only do once
  161.     ASSERT(lpszResourceName != NULL);
  162.  
  163.     HINSTANCE hInst = AfxFindResourceHandle(lpszResourceName, RT_ACCELERATOR);
  164.     m_hAccelTable = ::LoadAccelerators(hInst, lpszResourceName);
  165.     return (m_hAccelTable != NULL);
  166. }
  167.  
  168. HACCEL CFrameWnd::GetDefaultAccelerator()
  169. {
  170.     // use document specific accelerator table over m_hAccelTable
  171.     HACCEL hAccelTable = m_hAccelTable;
  172.     HACCEL hAccel;
  173.     CDocument* pDoc = GetActiveDocument();
  174.     if (pDoc != NULL && (hAccel = pDoc->GetDefaultAccelerator()) != NULL)
  175.         hAccelTable = hAccel;
  176.  
  177.     return hAccelTable;
  178. }
  179.  
  180. BOOL CFrameWnd::PreTranslateMessage(MSG* pMsg)
  181. {
  182.     // check for special cancel modes for combo boxes
  183.     if (pMsg->message == WM_LBUTTONDOWN || pMsg->message == WM_NCLBUTTONDOWN)
  184.         AfxCancelModes(pMsg->hwnd);    // filter clicks
  185.  
  186.     // allow tooltip messages to be filtered
  187.     if (CWnd::PreTranslateMessage(pMsg))
  188.         return TRUE;
  189.  
  190. #ifndef _AFX_NO_OLE_SUPPORT
  191.     // allow hook to consume message
  192.     if (m_pNotifyHook != NULL && m_pNotifyHook->OnPreTranslateMessage(pMsg))
  193.         return TRUE;
  194. #endif
  195.  
  196.     if (pMsg->message >= WM_KEYFIRST && pMsg->message <= WM_KEYLAST)
  197.     {
  198.         // finally, translate the message
  199.         HACCEL hAccel = GetDefaultAccelerator();
  200.         return hAccel != NULL &&  ::TranslateAccelerator(m_hWnd, hAccel, pMsg);
  201.     }
  202.     return FALSE;
  203. }
  204.  
  205. void CFrameWnd::PostNcDestroy()
  206. {
  207.     // default for frame windows is to allocate them on the heap
  208.     //  the default post-cleanup is to 'delete this'.
  209.     // never explicitly call 'delete' on a CFrameWnd, use DestroyWindow instead
  210.     delete this;
  211. }
  212.  
  213. void CFrameWnd::OnPaletteChanged(CWnd* pFocusWnd)
  214. {
  215.     CWnd::OnPaletteChanged(pFocusWnd);
  216. #ifndef _AFX_NO_OLE_SUPPORT
  217.     if (m_pNotifyHook != NULL)
  218.         m_pNotifyHook->OnPaletteChanged(pFocusWnd);
  219. #endif
  220. }
  221.  
  222. BOOL CFrameWnd::OnQueryNewPalette()
  223. {
  224. #ifndef _AFX_NO_OLE_SUPPORT
  225.     if (m_pNotifyHook != NULL && m_pNotifyHook->OnQueryNewPalette())
  226.         return TRUE;
  227. #endif
  228.     return CWnd::OnQueryNewPalette();
  229. }
  230.  
  231. /////////////////////////////////////////////////////////////////////////////
  232. // CFrameWnd support for context sensitive help.
  233.  
  234. void CFrameWnd::ExitHelpMode()
  235. {
  236.     // if not in help mode currently, this is a no-op
  237.     if (!m_bHelpMode)
  238.         return;
  239.  
  240.     // only post new WM_EXITHELPMODE message if one doesn't already exist
  241.     //  in the queue.
  242.     MSG msg;
  243.     if (!::PeekMessage(&msg, m_hWnd, WM_EXITHELPMODE, WM_EXITHELPMODE,
  244.         PM_REMOVE|PM_NOYIELD))
  245.     {
  246.         VERIFY(::PostMessage(m_hWnd, WM_EXITHELPMODE, 0, 0));
  247.     }
  248.  
  249.     // release capture if this window has it
  250.     if (::GetCapture() == m_hWnd)
  251.         ReleaseCapture();
  252.  
  253.     CFrameWnd* pFrameWnd = GetTopLevelFrame();
  254.     ASSERT_VALID(pFrameWnd);
  255.     pFrameWnd->m_bHelpMode = m_bHelpMode = HELP_INACTIVE;
  256.     PostMessage(WM_KICKIDLE);   // trigger idle update
  257. }
  258.  
  259. BOOL CFrameWnd::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
  260. {
  261.     CFrameWnd* pFrameWnd = GetTopLevelFrame();
  262.     ASSERT_VALID(pFrameWnd);
  263.     if (pFrameWnd->m_bHelpMode)
  264.     {
  265.         SetCursor(afxData.hcurHelp);
  266.         return TRUE;
  267.     }
  268.     return CWnd::OnSetCursor(pWnd, nHitTest, message);
  269. }
  270.  
  271. LRESULT CFrameWnd::OnCommandHelp(WPARAM, LPARAM lParam)
  272. {
  273.     if (lParam == 0)
  274.     {
  275.         if (IsTracking())
  276.             lParam = HID_BASE_COMMAND+m_nIDTracking;
  277.         else
  278.             lParam = HID_BASE_RESOURCE+m_nIDHelp;
  279.     }
  280.     if (lParam != 0)
  281.     {
  282.         CWinApp* pApp = AfxGetApp();
  283.         if (pApp != NULL)
  284.             pApp->WinHelp(lParam);
  285.         return TRUE;
  286.     }
  287.     return FALSE;
  288. }
  289.  
  290. LRESULT CFrameWnd::OnHelpHitTest(WPARAM, LPARAM)
  291. {
  292.     if (m_nIDHelp != 0)
  293.         return HID_BASE_RESOURCE+m_nIDHelp;
  294.     else
  295.         return 0;
  296. }
  297.  
  298. BOOL CFrameWnd::OnCommand(WPARAM wParam, LPARAM lParam)
  299.     // return TRUE if command invocation was attempted
  300. {
  301.     HWND hWndCtrl = (HWND)lParam;
  302.     UINT nID = LOWORD(wParam);
  303.  
  304.     CFrameWnd* pFrameWnd = GetTopLevelFrame();
  305.     ASSERT_VALID(pFrameWnd);
  306.     if (pFrameWnd->m_bHelpMode && hWndCtrl == NULL &&
  307.         nID != ID_HELP && nID != ID_DEFAULT_HELP && nID != ID_CONTEXT_HELP)
  308.     {
  309.         // route as help
  310.         if (!SendMessage(WM_COMMANDHELP, 0, HID_BASE_COMMAND+nID))
  311.             SendMessage(WM_COMMAND, ID_DEFAULT_HELP);
  312.         return TRUE;
  313.     }
  314.  
  315.     // route as normal command
  316.     return CWnd::OnCommand(wParam, lParam);
  317. }
  318.  
  319. /////////////////////////////////////////////////////////////////////////////
  320. // CFrameWnd support for modality
  321.  
  322. BOOL AFXAPI AfxIsDescendant(HWND hWndParent, HWND hWndChild)
  323.     // helper for detecting whether child descendent of parent
  324.     //  (works with owned popups as well)
  325. {
  326.     ASSERT(::IsWindow(hWndParent));
  327.     ASSERT(::IsWindow(hWndChild));
  328.  
  329.     do
  330.     {
  331.         if (hWndParent == hWndChild)
  332.             return TRUE;
  333.  
  334.         hWndChild = AfxGetParentOwner(hWndChild);
  335.     } while (hWndChild != NULL);
  336.  
  337.     return FALSE;
  338. }
  339.  
  340. void CFrameWnd::BeginModalState()
  341. {
  342.     ASSERT(m_hWnd != NULL);
  343.     ASSERT(::IsWindow(m_hWnd));
  344.  
  345.     // allow stacking, but don't do anything
  346.     if (++m_cModalStack > 1)
  347.         return;
  348.  
  349.     // determine top-level parent, since that is the true parent of any
  350.     //  modeless windows anyway...
  351.     CWnd* pParent = GetTopLevelParent();
  352.  
  353.     // first count all windows that need to be disabled
  354.     UINT nCount = 0;
  355.     HWND hWnd = ::GetWindow(::GetDesktopWindow(), GW_CHILD);
  356.     while (hWnd != NULL)
  357.     {
  358.         if (::IsWindowEnabled(hWnd) &&
  359.             CWnd::FromHandlePermanent(hWnd) != NULL &&
  360.             AfxIsDescendant(pParent->m_hWnd, hWnd) &&
  361.             ::SendMessage(hWnd, WM_DISABLEMODAL, 0, 0) == 0)
  362.         {
  363.             ++nCount;
  364.         }
  365.         hWnd = ::GetWindow(hWnd, GW_HWNDNEXT);
  366.     }
  367.     if (nCount == 0)
  368.         return;
  369.  
  370.     m_phWndDisable = new HWND[nCount+1];
  371.  
  372.     // disable all windows connected to this frame (and add them to the list)
  373.     UINT nIndex = 0;
  374.     hWnd = ::GetWindow(::GetDesktopWindow(), GW_CHILD);
  375.     while (hWnd != NULL)
  376.     {
  377.         if (::IsWindowEnabled(hWnd) &&
  378.             CWnd::FromHandlePermanent(hWnd) != NULL &&
  379.             AfxIsDescendant(pParent->m_hWnd, hWnd) &&
  380.             ::SendMessage(hWnd, WM_DISABLEMODAL, 0, 0) == 0)
  381.         {
  382.             ::EnableWindow(hWnd, FALSE);
  383.             ASSERT(nIndex < nCount);
  384.             m_phWndDisable[nIndex] = hWnd;
  385.             ++nIndex;
  386.         }
  387.         hWnd = ::GetWindow(hWnd, GW_HWNDNEXT);
  388.     }
  389.  
  390.     // terminate the list with a NULL
  391.     ASSERT(nIndex < nCount+1);
  392.     m_phWndDisable[nIndex] = NULL;
  393. }
  394.  
  395. void CFrameWnd::EndModalState()
  396. {
  397.     // pop one off the stack (don't undo modalness unless stack is down to zero)
  398.     if (m_cModalStack == 0 || --m_cModalStack > 0 || m_phWndDisable == NULL)
  399.         return;
  400.  
  401.     // enable all the windows disabled by BeginModalState
  402.     ASSERT(m_phWndDisable != NULL);
  403.     UINT nIndex = 0;
  404.     while (m_phWndDisable[nIndex] != NULL)
  405.     {
  406.         ASSERT(m_phWndDisable[nIndex] != NULL);
  407.         if (::IsWindow(m_phWndDisable[nIndex]))
  408.             ::EnableWindow(m_phWndDisable[nIndex], TRUE);
  409.         ++nIndex;
  410.     }
  411.     delete[] (void*)m_phWndDisable;
  412.     m_phWndDisable = NULL;
  413. }
  414.  
  415. void CFrameWnd::ShowOwnedWindows(BOOL bShow)
  416. {
  417.     // walk through all top-level windows
  418.     HWND hWnd = ::GetWindow(::GetDesktopWindow(), GW_CHILD);
  419.     while (hWnd != NULL)
  420.     {
  421.         CWnd* pWnd = CWnd::FromHandlePermanent(hWnd);
  422.         if (pWnd != NULL && m_hWnd != hWnd && AfxIsDescendant(m_hWnd, hWnd))
  423.         {
  424.             DWORD dwStyle = ::GetWindowLong(hWnd, GWL_STYLE);
  425.             if (!bShow && (dwStyle & (WS_VISIBLE|WS_DISABLED)) == WS_VISIBLE)
  426.             {
  427.                 ::ShowWindow(hWnd, SW_HIDE);
  428.                 pWnd->m_nFlags |= WF_TEMPHIDE;
  429.             }
  430.             else if (bShow && (dwStyle & (WS_VISIBLE|WS_DISABLED)) == 0 &&
  431.                 (pWnd->m_nFlags & WF_TEMPHIDE))
  432.             {
  433.                 ::ShowWindow(hWnd, SW_SHOWNOACTIVATE);
  434.                 pWnd->m_nFlags &= ~WF_TEMPHIDE;
  435.             }
  436.         }
  437.         hWnd = ::GetWindow(hWnd, GW_HWNDNEXT);
  438.     }
  439. }
  440.  
  441. void CFrameWnd::OnEnable(BOOL bEnable)
  442. {
  443.     if (bEnable && (m_nFlags & WF_STAYDISABLED))
  444.     {
  445.         // Work around for MAPI support. This makes sure the main window
  446.         // remains disabled even when the mail system is booting.
  447.         EnableWindow(FALSE);
  448.         ::SetFocus(NULL);
  449.         return;
  450.     }
  451.  
  452.     // only for top-level (and non-owned) windows
  453.     if (GetParent() != NULL)
  454.         return;
  455.  
  456.     // this causes modal dialogs to be "truly modal"
  457.     if (!bEnable && !InModalState())
  458.     {
  459.         ASSERT((m_nFlags & WF_MODALDISABLE) == 0);
  460.         m_nFlags |= WF_MODALDISABLE;
  461.         BeginModalState();
  462.     }
  463.     else if (bEnable && (m_nFlags & WF_MODALDISABLE))
  464.     {
  465.         m_nFlags &= ~WF_MODALDISABLE;
  466.         EndModalState();
  467.  
  468.         // cause normal focus logic to kick in
  469.         if (::GetActiveWindow() == m_hWnd)
  470.             SendMessage(WM_ACTIVATE, WA_ACTIVE);
  471.     }
  472.  
  473.     // force WM_NCACTIVATE because Windows may think it is unecessary
  474.     if (bEnable && (m_nFlags & WF_STAYACTIVE))
  475.         SendMessage(WM_NCACTIVATE, TRUE);
  476.     // force WM_NCACTIVATE for floating windows too
  477.     NotifyFloatingWindows(bEnable ? FS_ENABLE : FS_DISABLE);
  478. }
  479.  
  480. void CFrameWnd::NotifyFloatingWindows(DWORD dwFlags)
  481. {
  482.     ASSERT_VALID(this);
  483.     ASSERT(m_hWnd != NULL);
  484.  
  485.     // get top level parent frame window first unless this is a child window
  486.     CFrameWnd* pParent = (GetStyle() & WS_CHILD) ? this : GetTopLevelFrame();
  487.     ASSERT(pParent != NULL);
  488.     if (dwFlags & (FS_DEACTIVATE|FS_ACTIVATE))
  489.     {
  490.         // update parent window activation state
  491.         BOOL bActivate = !(dwFlags & FS_DEACTIVATE);
  492.         BOOL bEnabled = pParent->IsWindowEnabled();
  493.  
  494.         if (bActivate && bEnabled && pParent != this)
  495.         {
  496.             // Excel will try to Activate itself when it receives a
  497.             // WM_NCACTIVATE so we need to keep it from doing that here.
  498.             m_nFlags |= WF_KEEPMINIACTIVE;
  499.             pParent->SendMessage(WM_NCACTIVATE, TRUE);
  500.             m_nFlags &= ~WF_KEEPMINIACTIVE;
  501.         }
  502.         else
  503.         {
  504.             pParent->SendMessage(WM_NCACTIVATE, FALSE);
  505.         }
  506.     }
  507.  
  508.     // then update the state of all floating windows owned by the parent
  509.     HWND hWnd = ::GetWindow(::GetDesktopWindow(), GW_CHILD);
  510.     while (hWnd != NULL)
  511.     {
  512.         if (AfxIsDescendant(pParent->m_hWnd, hWnd))
  513.             ::SendMessage(hWnd, WM_FLOATSTATUS, dwFlags, 0);
  514.         hWnd = ::GetWindow(hWnd, GW_HWNDNEXT);
  515.     }
  516. }
  517.  
  518. /////////////////////////////////////////////////////////////////////////////
  519. // CFrameWnd second phase creation
  520.  
  521. BOOL CFrameWnd::PreCreateWindow(CREATESTRUCT& cs)
  522. {
  523.     if (cs.lpszClass == NULL)
  524.     {
  525.         VERIFY(AfxDeferRegisterClass(AFX_WNDFRAMEORVIEW_REG));
  526.         cs.lpszClass = _afxWndFrameOrView;  // COLOR_WINDOW background
  527.     }
  528.  
  529.     if ((cs.style & FWS_ADDTOTITLE) && afxData.bWin4)
  530.         cs.style |= FWS_PREFIXTITLE;
  531.  
  532.     if (afxData.bWin4)
  533.         cs.dwExStyle |= WS_EX_CLIENTEDGE;
  534.  
  535.     return TRUE;
  536. }
  537.  
  538. BOOL CFrameWnd::Create(LPCTSTR lpszClassName,
  539.     LPCTSTR lpszWindowName,
  540.     DWORD dwStyle,
  541.     const RECT& rect,
  542.     CWnd* pParentWnd,
  543.     LPCTSTR lpszMenuName,
  544.     DWORD dwExStyle,
  545.     CCreateContext* pContext)
  546. {
  547.     HMENU hMenu = NULL;
  548.     if (lpszMenuName != NULL)
  549.     {
  550.         // load in a menu that will get destroyed when window gets destroyed
  551.         HINSTANCE hInst = AfxFindResourceHandle(lpszMenuName, RT_MENU);
  552.         if ((hMenu = ::LoadMenu(hInst, lpszMenuName)) == NULL)
  553.         {
  554.             TRACE0("Warning: failed to load menu for CFrameWnd.\n");
  555.             PostNcDestroy();            // perhaps delete the C++ object
  556.             return FALSE;
  557.         }
  558.     }
  559.  
  560.     m_strTitle = lpszWindowName;    // save title for later
  561.  
  562.     if (!CreateEx(dwExStyle, lpszClassName, lpszWindowName, dwStyle,
  563.         rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
  564.         pParentWnd->GetSafeHwnd(), hMenu, (LPVOID)pContext))
  565.     {
  566.         TRACE0("Warning: failed to create CFrameWnd.\n");
  567.         if (hMenu != NULL)
  568.             DestroyMenu(hMenu);
  569.         return FALSE;
  570.     }
  571.  
  572.     return TRUE;
  573. }
  574.  
  575. CWnd* CFrameWnd::CreateView(CCreateContext* pContext, UINT nID)
  576. {
  577.     ASSERT(m_hWnd != NULL);
  578.     ASSERT(::IsWindow(m_hWnd));
  579.     ASSERT(pContext != NULL);
  580.     ASSERT(pContext->m_pNewViewClass != NULL);
  581.  
  582.     // Note: can be a CWnd with PostNcDestroy self cleanup
  583.     CWnd* pView = (CWnd*)pContext->m_pNewViewClass->CreateObject();
  584.     if (pView == NULL)
  585.     {
  586.         TRACE1("Warning: Dynamic create of view type %hs failed.\n",
  587.             pContext->m_pNewViewClass->m_lpszClassName);
  588.         return NULL;
  589.     }
  590.     ASSERT_KINDOF(CWnd, pView);
  591.  
  592.     // views are always created with a border!
  593.     if (!pView->Create(NULL, NULL, AFX_WS_DEFAULT_VIEW,
  594.         CRect(0,0,0,0), this, nID, pContext))
  595.     {
  596.         TRACE0("Warning: could not create view for frame.\n");
  597.         return NULL;        // can't continue without a view
  598.     }
  599.  
  600.     if (afxData.bWin4 && (pView->GetExStyle() & WS_EX_CLIENTEDGE))
  601.     {
  602.         // remove the 3d style from the frame, since the view is
  603.         //  providing it.
  604.         // make sure to recalc the non-client area
  605.         ModifyStyleEx(WS_EX_CLIENTEDGE, 0, SWP_FRAMECHANGED);
  606.     }
  607.     return pView;
  608. }
  609.  
  610. BOOL CFrameWnd::OnCreateClient(LPCREATESTRUCT, CCreateContext* pContext)
  611. {
  612.     // default create client will create a view if asked for it
  613.     if (pContext != NULL && pContext->m_pNewViewClass != NULL)
  614.     {
  615.         if (CreateView(pContext, AFX_IDW_PANE_FIRST) == NULL)
  616.             return FALSE;
  617.     }
  618.     return TRUE;
  619. }
  620.  
  621. int CFrameWnd::OnCreate(LPCREATESTRUCT lpcs)
  622. {
  623.     CCreateContext* pContext = (CCreateContext*)lpcs->lpCreateParams;
  624.     return OnCreateHelper(lpcs, pContext);
  625. }
  626.  
  627. int CFrameWnd::OnCreateHelper(LPCREATESTRUCT lpcs, CCreateContext* pContext)
  628. {
  629.     if (CWnd::OnCreate(lpcs) == -1)
  630.         return -1;
  631.  
  632.     // create special children first
  633.     if (!OnCreateClient(lpcs, pContext))
  634.     {
  635.         TRACE0("Failed to create client pane/view for frame.\n");
  636.         return -1;
  637.     }
  638.  
  639.     // post message for initial message string
  640.     PostMessage(WM_SETMESSAGESTRING, AFX_IDS_IDLEMESSAGE);
  641.  
  642.     // make sure the child windows have been properly sized
  643.     RecalcLayout();
  644.  
  645.     return 0;   // create ok
  646. }
  647.  
  648. LPCTSTR CFrameWnd::GetIconWndClass(DWORD dwDefaultStyle, UINT nIDResource)
  649. {
  650.     ASSERT_VALID_IDR(nIDResource);
  651.     HINSTANCE hInst = AfxFindResourceHandle(
  652.         MAKEINTRESOURCE(nIDResource), RT_GROUP_ICON);
  653.     HICON hIcon = ::LoadIcon(hInst, MAKEINTRESOURCE(nIDResource));
  654.     if (hIcon != NULL)
  655.     {
  656.         CREATESTRUCT cs;
  657.         memset(&cs, 0, sizeof(CREATESTRUCT));
  658.         cs.style = dwDefaultStyle;
  659.         PreCreateWindow(cs);
  660.             // will fill lpszClassName with default WNDCLASS name
  661.             // ignore instance handle from PreCreateWindow.
  662.  
  663.         WNDCLASS wndcls;
  664.         if (cs.lpszClass != NULL &&
  665.             GetClassInfo(AfxGetInstanceHandle(), cs.lpszClass, &wndcls) &&
  666.             wndcls.hIcon != hIcon)
  667.         {
  668.             // register a very similar WNDCLASS
  669.             return AfxRegisterWndClass(wndcls.style,
  670.                 wndcls.hCursor, wndcls.hbrBackground, hIcon);
  671.         }
  672.     }
  673.     return NULL;        // just use the default
  674. }
  675.  
  676. BOOL CFrameWnd::LoadFrame(UINT nIDResource, DWORD dwDefaultStyle,
  677.     CWnd* pParentWnd, CCreateContext* pContext)
  678. {
  679.     // only do this once
  680.     ASSERT_VALID_IDR(nIDResource);
  681.     ASSERT(m_nIDHelp == 0 || m_nIDHelp == nIDResource);
  682.  
  683.     m_nIDHelp = nIDResource;    // ID for help context (+HID_BASE_RESOURCE)
  684.  
  685.     CString strFullString;
  686.     if (strFullString.LoadString(nIDResource))
  687.         AfxExtractSubString(m_strTitle, strFullString, 0);    // first sub-string
  688.  
  689.     VERIFY(AfxDeferRegisterClass(AFX_WNDFRAMEORVIEW_REG));
  690.  
  691.     // attempt to create the window
  692.     LPCTSTR lpszClass = GetIconWndClass(dwDefaultStyle, nIDResource);
  693.     LPCTSTR lpszTitle = m_strTitle;
  694.     if (!Create(lpszClass, lpszTitle, dwDefaultStyle, rectDefault,
  695.       pParentWnd, MAKEINTRESOURCE(nIDResource), 0L, pContext))
  696.     {
  697.         return FALSE;   // will self destruct on failure normally
  698.     }
  699.  
  700.     // save the default menu handle
  701.     ASSERT(m_hWnd != NULL);
  702.     m_hMenuDefault = ::GetMenu(m_hWnd);
  703.  
  704.     // load accelerator resource
  705.     LoadAccelTable(MAKEINTRESOURCE(nIDResource));
  706.  
  707.     if (pContext == NULL)   // send initial update
  708.         SendMessageToDescendants(WM_INITIALUPDATE, 0, 0, TRUE, TRUE);
  709.  
  710.     return TRUE;
  711. }
  712.  
  713. void CFrameWnd::OnUpdateFrameMenu(HMENU hMenuAlt)
  714. {
  715.     if (hMenuAlt == NULL)
  716.     {
  717.         // attempt to get default menu from document
  718.         CDocument* pDoc = GetActiveDocument();
  719.         if (pDoc != NULL)
  720.             hMenuAlt = pDoc->GetDefaultMenu();
  721.         // use default menu stored in frame if none from document
  722.         if (hMenuAlt == NULL)
  723.             hMenuAlt = m_hMenuDefault;
  724.     }
  725.     // finally, set the menu
  726.     ::SetMenu(m_hWnd, hMenuAlt);
  727. }
  728.  
  729. void CFrameWnd::InitialUpdateFrame(CDocument* pDoc, BOOL bMakeVisible)
  730. {
  731.     // if the frame does not have an active view, set to first pane
  732.     CView* pView = NULL;
  733.     if (GetActiveView() == NULL)
  734.     {
  735.         CWnd* pWnd = GetDescendantWindow(AFX_IDW_PANE_FIRST, TRUE);
  736.         if (pWnd != NULL && pWnd->IsKindOf(RUNTIME_CLASS(CView)))
  737.         {
  738.             pView = (CView*)pWnd;
  739.             SetActiveView(pView, FALSE);
  740.         }
  741.     }
  742.  
  743.     if (bMakeVisible)
  744.     {
  745.         // send initial update to all views (and other controls) in the frame
  746.         SendMessageToDescendants(WM_INITIALUPDATE, 0, 0, TRUE, TRUE);
  747.  
  748.         // give view a chance to save the focus (CFormView needs this)
  749.         if (pView != NULL)
  750.             pView->OnActivateFrame(WA_INACTIVE, this);
  751.  
  752.         // finally, activate the frame
  753.         // (send the default show command unless the main desktop window)
  754.         int nCmdShow = -1;      // default
  755.         CWinApp* pApp = AfxGetApp();
  756.         if (pApp != NULL && pApp->m_pMainWnd == this)
  757.         {
  758.             nCmdShow = pApp->m_nCmdShow; // use the parameter from WinMain
  759.             pApp->m_nCmdShow = -1; // set to default after first time
  760.         }
  761.         ActivateFrame(nCmdShow);
  762.         if (pView != NULL)
  763.             pView->OnActivateView(TRUE, pView, pView);
  764.     }
  765.  
  766.     // update frame counts and frame title (may already have been visible)
  767.     if (pDoc != NULL)
  768.         pDoc->UpdateFrameCounts();
  769.     OnUpdateFrameTitle(TRUE);
  770. }
  771.  
  772. /////////////////////////////////////////////////////////////////////////////
  773. // CFrameWnd closing down
  774.  
  775. void CFrameWnd::OnClose()
  776. {
  777.     if (m_lpfnCloseProc != NULL && !(*m_lpfnCloseProc)(this))
  778.         return;
  779.  
  780.     // Note: only queries the active document
  781.     CDocument* pDocument = GetActiveDocument();
  782.     if (pDocument != NULL && !pDocument->CanCloseFrame(this))
  783.     {
  784.         // document can't close right now -- don't close it
  785.         return;
  786.     }
  787.     CWinApp* pApp = AfxGetApp();
  788.     if (pApp != NULL && pApp->m_pMainWnd == this)
  789.     {
  790.         // attempt to save all documents
  791.         if (pDocument == NULL && !pApp->SaveAllModified())
  792.             return;     // don't close it
  793.  
  794.         // hide the application's windows before closing all the documents
  795.         pApp->HideApplication();
  796.  
  797.         // close all documents first
  798.         pApp->CloseAllDocuments(FALSE);
  799.  
  800.         // don't exit if there are outstanding component objects
  801.         if (!AfxOleCanExitApp())
  802.         {
  803.             // take user out of control of the app
  804.             AfxOleSetUserCtrl(FALSE);
  805.  
  806.             // don't destroy the main window and close down just yet
  807.             //  (there are outstanding component (OLE) objects)
  808.             return;
  809.         }
  810.  
  811.         // there are cases where destroying the documents may destroy the
  812.         //  main window of the application.
  813.         if (!afxContextIsDLL && pApp->m_pMainWnd == NULL)
  814.         {
  815.             AfxPostQuitMessage(0);
  816.             return;
  817.         }
  818.     }
  819.  
  820.     // detect the case that this is the last frame on the document and
  821.     // shut down with OnCloseDocument instead.
  822.     if (pDocument != NULL && pDocument->m_bAutoDelete)
  823.     {
  824.         BOOL bOtherFrame = FALSE;
  825.         POSITION pos = pDocument->GetFirstViewPosition();
  826.         while (pos != NULL)
  827.         {
  828.             CView* pView = pDocument->GetNextView(pos);
  829.             ASSERT_VALID(pView);
  830.             if (pView->GetParentFrame() != this)
  831.             {
  832.                 bOtherFrame = TRUE;
  833.                 break;
  834.             }
  835.         }
  836.         if (!bOtherFrame)
  837.         {
  838.             pDocument->OnCloseDocument();
  839.             return;
  840.         }
  841.  
  842.         // allow the document to cleanup before the window is destroyed
  843.         pDocument->PreCloseFrame(this);
  844.     }
  845.  
  846.     // then destroy the window
  847.     DestroyWindow();
  848. }
  849.  
  850. void CFrameWnd::OnDestroy()
  851. {
  852.     DestroyDockBars();
  853.  
  854.     // reset menu to default before final shutdown
  855.     if (m_hMenuDefault != NULL && ::GetMenu(m_hWnd) != m_hMenuDefault)
  856.     {
  857.         ::SetMenu(m_hWnd, m_hMenuDefault);
  858.         ASSERT(::GetMenu(m_hWnd) == m_hMenuDefault);
  859.     }
  860.  
  861.     // Automatically quit when the main window is destroyed.
  862.     CWinApp* pApp = AfxGetApp();
  863.     if (pApp != NULL && pApp->m_pMainWnd == this)
  864.     {
  865.         // closing the main application window
  866.         ::WinHelp(m_hWnd, NULL, HELP_QUIT, 0L);
  867.  
  868.         // will call PostQuitMessage in CWnd::OnNcDestroy
  869.     }
  870.     CWnd::OnDestroy();
  871. }
  872.  
  873. void CFrameWnd::RemoveControlBar(CControlBar *pBar)
  874. {
  875.     POSITION pos = m_listControlBars.Find(pBar);
  876.     if (pos != NULL)
  877.         m_listControlBars.RemoveAt(pos);
  878. }
  879.  
  880. /////////////////////////////////////////////////////////////////////////////
  881. // CFrameWnd command/message routing
  882.  
  883. BOOL CFrameWnd::OnCmdMsg(UINT nID, int nCode, void* pExtra,
  884.     AFX_CMDHANDLERINFO* pHandlerInfo)
  885. {
  886.     CPushRoutingFrame push(this);
  887.  
  888.     // pump through current view FIRST
  889.     CView* pView = GetActiveView();
  890.     if (pView != NULL && pView->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
  891.         return TRUE;
  892.  
  893.     // then pump through frame
  894.     if (CWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
  895.         return TRUE;
  896.  
  897.     // last but not least, pump through app
  898.     CWinApp* pApp = AfxGetApp();
  899.     if (pApp != NULL && pApp->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
  900.         return TRUE;
  901.  
  902.     return FALSE;
  903. }
  904.  
  905. // Delegate scroll messages to active view as well
  906. void CFrameWnd::OnHScroll(UINT, UINT, CScrollBar*)
  907. {
  908.     CWnd* pActiveView = GetActiveView();
  909.     if (pActiveView != NULL)
  910.     {
  911.         const MSG* pMsg = GetCurrentMessage();
  912.         pActiveView->SendMessage(WM_HSCROLL, pMsg->wParam, pMsg->lParam);
  913.     }
  914. }
  915.  
  916. void CFrameWnd::OnVScroll(UINT, UINT, CScrollBar*)
  917. {
  918.     CWnd* pActiveView = GetActiveView();
  919.     if (pActiveView != NULL)
  920.     {
  921.         const MSG* pMsg = GetCurrentMessage();
  922.         pActiveView->SendMessage(WM_VSCROLL, pMsg->wParam, pMsg->lParam);
  923.     }
  924. }
  925.  
  926. LRESULT CFrameWnd::OnActivateTopLevel(WPARAM wParam, LPARAM lParam)
  927. {
  928.     CWnd::OnActivateTopLevel(wParam, lParam);
  929.  
  930.     // exit Shift+F1 help mode on activation changes
  931.     ExitHelpMode();
  932.  
  933. #ifndef _AFX_NO_OLE_SUPPORT
  934.     // allow OnFrameWindowActivate to be sent to in-place items
  935.     if (m_pNotifyHook != NULL)
  936.     {
  937.         // activate when active and when not minimized
  938.         m_pNotifyHook->OnActivate(
  939.             LOWORD(wParam) != WA_INACTIVE && !HIWORD(wParam));
  940.     }
  941. #endif
  942.  
  943.     // deactivate current active view
  944.     if (AfxGetThread()->m_pMainWnd == this)
  945.     {
  946.         CView* pActiveView = GetActiveView();
  947.         if (pActiveView == NULL)
  948.             pActiveView = GetActiveFrame()->GetActiveView();
  949.         if (pActiveView != NULL)
  950.             pActiveView->OnActivateView(FALSE, pActiveView, pActiveView);
  951.     }
  952.  
  953.     // force idle processing to update any key state indicators
  954.     PostMessage(WM_KICKIDLE);
  955.  
  956.     return 0;
  957. }
  958.  
  959. void CFrameWnd::OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized)
  960. {
  961.     CWnd::OnActivate(nState, pWndOther, bMinimized);
  962.  
  963.     // get top level frame unless this is a child window
  964.     // determine if window should be active or not
  965.     CFrameWnd* pTopLevel = (GetStyle() & WS_CHILD) ? this : GetTopLevelFrame();
  966.     ASSERT(pTopLevel != NULL);
  967.     CWnd* pActive = (nState == WA_INACTIVE ? pWndOther : this);
  968.     BOOL bStayActive =
  969.         (pTopLevel == pActive ||
  970.         (pTopLevel == pActive->GetTopLevelFrame() &&
  971.         (pActive == pTopLevel ||
  972.             pActive->SendMessage(WM_FLOATSTATUS, FS_SYNCACTIVE) != 0)));
  973.     pTopLevel->m_nFlags &= ~WF_STAYACTIVE;
  974.     if (bStayActive)
  975.         pTopLevel->m_nFlags |= WF_STAYACTIVE;
  976.  
  977.     // sync floating windows to the new state
  978.     NotifyFloatingWindows(bStayActive ? FS_ACTIVATE : FS_DEACTIVATE);
  979.  
  980.     // get active view (use active frame if no active view)
  981.     CView* pActiveView = GetActiveView();
  982.     if (pActiveView == NULL)
  983.         pActiveView = GetActiveFrame()->GetActiveView();
  984.  
  985.     // when frame gets activated, re-activate current view
  986.     if (pActiveView != NULL)
  987.     {
  988.         if (nState != WA_INACTIVE && !bMinimized)
  989.             pActiveView->OnActivateView(TRUE, pActiveView, pActiveView);
  990.  
  991.         // always notify the view of frame activations
  992.         pActiveView->OnActivateFrame(nState, this);
  993.     }
  994. }
  995.  
  996. BOOL CFrameWnd::OnNcActivate(BOOL bActive)
  997. {
  998.     // stay active if WF_STAYACTIVE bit is on
  999.     if (m_nFlags & WF_STAYACTIVE)
  1000.         bActive = TRUE;
  1001.  
  1002.     // but do not stay active if the window is disabled
  1003.     if (!IsWindowEnabled())
  1004.         bActive = FALSE;
  1005.  
  1006.     // do not call the base class because it will call Default()
  1007.     //  and we may have changed bActive.
  1008.     return (BOOL)DefWindowProc(WM_NCACTIVATE, bActive, 0L);
  1009. }
  1010.  
  1011. void CFrameWnd::OnSysCommand(UINT nID, LONG lParam)
  1012. {
  1013.     CFrameWnd* pFrameWnd = GetTopLevelFrame();
  1014.     ASSERT_VALID(pFrameWnd);
  1015.  
  1016.     // set status bar as appropriate
  1017.     UINT nItemID = (nID & 0xFFF0);
  1018.  
  1019.     // don't interfere with system commands if not in help mode
  1020.     if (pFrameWnd->m_bHelpMode)
  1021.     {
  1022.         switch (nItemID)
  1023.         {
  1024.         case SC_SIZE:
  1025.         case SC_MOVE:
  1026.         case SC_MINIMIZE:
  1027.         case SC_MAXIMIZE:
  1028.         case SC_NEXTWINDOW:
  1029.         case SC_PREVWINDOW:
  1030.         case SC_CLOSE:
  1031.         case SC_RESTORE:
  1032.         case SC_TASKLIST:
  1033.             if (!SendMessage(WM_COMMANDHELP, 0,
  1034.               HID_BASE_COMMAND+ID_COMMAND_FROM_SC(nItemID)))
  1035.                 SendMessage(WM_COMMAND, ID_DEFAULT_HELP);
  1036.             return;
  1037.         }
  1038.     }
  1039.  
  1040.     // call default functionality
  1041.     CWnd::OnSysCommand(nID, lParam);
  1042. }
  1043.  
  1044. /////////////////////////////////////////////////////////////////////////////
  1045. // default frame processing
  1046.  
  1047. // default drop processing will attempt to open the file
  1048. void CFrameWnd::OnDropFiles(HDROP hDropInfo)
  1049. {
  1050.     SetActiveWindow();      // activate us first !
  1051.     UINT nFiles = ::DragQueryFile(hDropInfo, (UINT)-1, NULL, 0);
  1052.  
  1053.     CWinApp* pApp = AfxGetApp();
  1054.     ASSERT(pApp != NULL);
  1055.     for (UINT iFile = 0; iFile < nFiles; iFile++)
  1056.     {
  1057.         TCHAR szFileName[_MAX_PATH];
  1058.         ::DragQueryFile(hDropInfo, iFile, szFileName, _MAX_PATH);
  1059.         pApp->OpenDocumentFile(szFileName);
  1060.     }
  1061.     ::DragFinish(hDropInfo);
  1062. }
  1063.  
  1064. // query end session for main frame will attempt to close it all down
  1065. BOOL CFrameWnd::OnQueryEndSession()
  1066. {
  1067.     CWinApp* pApp = AfxGetApp();
  1068.     if (pApp != NULL && pApp->m_pMainWnd == this)
  1069.         return pApp->SaveAllModified();
  1070.  
  1071.     return TRUE;
  1072. }
  1073.  
  1074. // when Windows session ends, close all documents
  1075. void CFrameWnd::OnEndSession(BOOL bEnding)
  1076. {
  1077.     if (!bEnding)
  1078.         return;
  1079.  
  1080.     CWinApp* pApp = AfxGetApp();
  1081.     if (pApp != NULL && pApp->m_pMainWnd == this)
  1082.     {
  1083.         AfxOleSetUserCtrl(TRUE);    // keeps from randomly shutting down
  1084.         pApp->CloseAllDocuments(TRUE);
  1085.  
  1086.         // allow application to save settings, etc.
  1087.         pApp->ExitInstance();
  1088.     }
  1089. }
  1090.  
  1091. /////////////////////////////////////////////////////////////////////////////
  1092. // Support for Shell DDE Execute messages
  1093.  
  1094. LRESULT CFrameWnd::OnDDEInitiate(WPARAM wParam, LPARAM lParam)
  1095. {
  1096.     CWinApp* pApp = AfxGetApp();
  1097.     if (pApp != NULL &&
  1098.         LOWORD(lParam) != 0 && HIWORD(lParam) != 0 &&
  1099.         (ATOM)LOWORD(lParam) == pApp->m_atomApp &&
  1100.         (ATOM)HIWORD(lParam) == pApp->m_atomSystemTopic)
  1101.     {
  1102.         // make duplicates of the incoming atoms (really adding a reference)
  1103.         TCHAR szAtomName[_MAX_PATH];
  1104.         VERIFY(GlobalGetAtomName(pApp->m_atomApp,
  1105.             szAtomName, _MAX_PATH - 1) != 0);
  1106.         VERIFY(GlobalAddAtom(szAtomName) == pApp->m_atomApp);
  1107.         VERIFY(GlobalGetAtomName(pApp->m_atomSystemTopic,
  1108.             szAtomName, _MAX_PATH - 1) != 0);
  1109.         VERIFY(GlobalAddAtom(szAtomName) == pApp->m_atomSystemTopic);
  1110.  
  1111.         // send the WM_DDE_ACK (caller will delete duplicate atoms)
  1112.         ::SendMessage((HWND)wParam, WM_DDE_ACK, (WPARAM)m_hWnd,
  1113.             MAKELPARAM(pApp->m_atomApp, pApp->m_atomSystemTopic));
  1114.     }
  1115.     return 0L;
  1116. }
  1117.  
  1118. // always ACK the execute command - even if we do nothing
  1119. LRESULT CFrameWnd::OnDDEExecute(WPARAM wParam, LPARAM lParam)
  1120. {
  1121.     // unpack the DDE message
  1122.     UINT unused;
  1123.     HGLOBAL hData;
  1124.     VERIFY(UnpackDDElParam(WM_DDE_EXECUTE, lParam, &unused, (UINT*)&hData));
  1125.  
  1126.     // get the command string
  1127.     TCHAR szCommand[_MAX_PATH * 2];
  1128.     LPCTSTR lpsz = (LPCTSTR)GlobalLock(hData);
  1129.     lstrcpyn(szCommand, lpsz, _countof(szCommand));
  1130.     GlobalUnlock(hData);
  1131.  
  1132.     // acknowledge now - before attempting to execute
  1133.     ::PostMessage((HWND)wParam, WM_DDE_ACK, (WPARAM)m_hWnd,
  1134.         ReuseDDElParam(lParam, WM_DDE_EXECUTE, WM_DDE_ACK,
  1135.         (UINT)0x8000, (UINT)hData));
  1136.  
  1137.     // don't execute the command when the window is disabled
  1138.     if (!IsWindowEnabled())
  1139.     {
  1140.         TRACE1("Warning: DDE command '%s' ignored because window is disabled.\n",
  1141.             szCommand);
  1142.         return 0;
  1143.     }
  1144.  
  1145.     // execute the command
  1146.     if (!AfxGetApp()->OnDDECommand(szCommand))
  1147.         TRACE1("Error: failed to execute DDE command '%s'.\n", szCommand);
  1148.  
  1149.     return 0L;
  1150. }
  1151.  
  1152. LRESULT CFrameWnd::OnDDETerminate(WPARAM wParam, LPARAM lParam)
  1153. {
  1154.     ::PostMessage((HWND)wParam, WM_DDE_TERMINATE, (WPARAM)m_hWnd, lParam);
  1155.     return 0L;
  1156. }
  1157.  
  1158. /////////////////////////////////////////////////////////////////////////////
  1159. // CFrameWnd attributes
  1160.  
  1161. CView* CFrameWnd::GetActiveView() const
  1162. {
  1163.     ASSERT(m_pViewActive == NULL ||
  1164.         m_pViewActive->IsKindOf(RUNTIME_CLASS(CView)));
  1165.     return m_pViewActive;
  1166. }
  1167.  
  1168. void CFrameWnd::SetActiveView(CView* pViewNew, BOOL bNotify)
  1169. {
  1170. #ifdef _DEBUG
  1171.     if (pViewNew != NULL)
  1172.     {
  1173.         ASSERT(IsChild(pViewNew));
  1174.         ASSERT_KINDOF(CView, pViewNew);
  1175.     }
  1176. #endif //_DEBUG
  1177.  
  1178.     CView* pViewOld = m_pViewActive;
  1179.     if (pViewNew == pViewOld)
  1180.         return;     // do not re-activate if SetActiveView called more than once
  1181.  
  1182.     m_pViewActive = NULL;   // no active for the following processing
  1183.  
  1184.     // deactivate the old one
  1185.     if (pViewOld != NULL)
  1186.         pViewOld->OnActivateView(FALSE, pViewNew, pViewOld);
  1187.  
  1188.     // if the OnActivateView moves the active window,
  1189.     //    that will veto this change
  1190.     if (m_pViewActive != NULL)
  1191.         return;     // already set
  1192.     m_pViewActive = pViewNew;
  1193.  
  1194.     // activate
  1195.     if (pViewNew != NULL && bNotify)
  1196.         pViewNew->OnActivateView(TRUE, pViewNew, pViewOld);
  1197. }
  1198.  
  1199. /////////////////////////////////////////////////////////////////////////////
  1200. // Special view swapping/activation
  1201.  
  1202. void CFrameWnd::OnSetFocus(CWnd* pOldWnd)
  1203. {
  1204.     if (m_pViewActive != NULL)
  1205.         m_pViewActive->SetFocus();
  1206.     else
  1207.         CWnd::OnSetFocus(pOldWnd);
  1208. }
  1209.  
  1210. CDocument* CFrameWnd::GetActiveDocument()
  1211. {
  1212.     ASSERT_VALID(this);
  1213.     CView* pView = GetActiveView();
  1214.     if (pView != NULL)
  1215.         return pView->GetDocument();
  1216.     return NULL;
  1217. }
  1218.  
  1219. void CFrameWnd::ShowControlBar(CControlBar* pBar, BOOL bShow, BOOL bDelay)
  1220. {
  1221.     ASSERT(pBar != NULL);
  1222.     CFrameWnd* pParentFrame = pBar->GetDockingFrame();
  1223.     ASSERT(pParentFrame->GetTopLevelParent() == GetTopLevelParent());
  1224.         // parent frame of bar must be related
  1225.  
  1226.     if (bDelay)
  1227.     {
  1228.         pBar->DelayShow(bShow);
  1229.         pParentFrame->DelayRecalcLayout();
  1230.     }
  1231.     else
  1232.     {
  1233.         pBar->SetWindowPos(NULL, 0, 0, 0, 0,
  1234.             SWP_NOZORDER|SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE|
  1235.             (bShow ? SWP_SHOWWINDOW : SWP_HIDEWINDOW));
  1236.         // call DelayShow to clear any contradictory DelayShow
  1237.         pBar->DelayShow(bShow);
  1238.         if (bShow || !pBar->IsFloating())
  1239.             pParentFrame->RecalcLayout(FALSE);
  1240.     }
  1241.  
  1242.     // show or hide the floating frame as appropriate
  1243.     if (pBar->IsFloating())
  1244.     {
  1245.         int nVisCount = pBar->m_pDockBar != NULL ?
  1246.             pBar->m_pDockBar->GetDockedVisibleCount() : bShow ? 1 : 0;
  1247.         if (nVisCount == 1 && bShow)
  1248.         {
  1249.             pParentFrame->m_nShowDelay = -1;
  1250.             if (bDelay)
  1251.             {
  1252.                 pParentFrame->m_nShowDelay = SW_SHOWNA;
  1253.                 pParentFrame->RecalcLayout(FALSE);
  1254.             }
  1255.             else
  1256.                 pParentFrame->ShowWindow(SW_SHOWNA);
  1257.         }
  1258.         else if (nVisCount == 0)
  1259.         {
  1260.             ASSERT(!bShow);
  1261.             pParentFrame->m_nShowDelay = -1;
  1262.             if (bDelay)
  1263.                 pParentFrame->m_nShowDelay = SW_HIDE;
  1264.             else
  1265.                 pParentFrame->ShowWindow(SW_HIDE);
  1266.         }
  1267.         else if (!bDelay)
  1268.         {
  1269.             pParentFrame->RecalcLayout(FALSE);
  1270.         }
  1271.     }
  1272. }
  1273.  
  1274. /////////////////////////////////////////////////////////////////////////////
  1275. // Command prompts
  1276.  
  1277. void CFrameWnd::OnInitMenu(CMenu* pMenu)
  1278. {
  1279. #ifndef _AFX_NO_OLE_SUPPORT
  1280.     // allow hook to consume message
  1281.     if (m_pNotifyHook != NULL)
  1282.     {
  1283. #ifdef _AFXDLL
  1284.         ASSERT(m_pModuleState != NULL);
  1285.         if (m_pModuleState->m_dwVersion >= 0x423)
  1286. #endif
  1287.             m_pNotifyHook->OnInitMenu(pMenu);
  1288. #endif
  1289.     }
  1290.  
  1291.     Default();
  1292. }
  1293.  
  1294. void CFrameWnd::OnInitMenuPopup(CMenu* pMenu, UINT nIndex, BOOL bSysMenu)
  1295. {
  1296.     AfxCancelModes(m_hWnd);
  1297.  
  1298.     if (bSysMenu)
  1299.         return;     // don't support system menu
  1300.  
  1301. #ifndef _AFX_NO_OLE_SUPPORT
  1302.     // allow hook to consume message
  1303.     if (m_pNotifyHook != NULL)
  1304.     {
  1305. #ifdef _AFXDLL
  1306.         ASSERT(m_pModuleState != NULL);
  1307.         if (m_pModuleState->m_dwVersion >= 0x423)
  1308. #endif
  1309.             if (m_pNotifyHook->OnInitMenuPopup(pMenu, nIndex, bSysMenu))
  1310.                 return;
  1311.     }
  1312. #endif
  1313.  
  1314.     ASSERT(pMenu != NULL);
  1315.     // check the enabled state of various menu items
  1316.  
  1317.     CCmdUI state;
  1318.     state.m_pMenu = pMenu;
  1319.     ASSERT(state.m_pOther == NULL);
  1320.     ASSERT(state.m_pParentMenu == NULL);
  1321.  
  1322.     // determine if menu is popup in top-level menu and set m_pOther to
  1323.     //  it if so (m_pParentMenu == NULL indicates that it is secondary popup)
  1324.     HMENU hParentMenu;
  1325.     if (AfxGetThreadState()->m_hTrackingMenu == pMenu->m_hMenu)
  1326.         state.m_pParentMenu = pMenu;    // parent == child for tracking popup
  1327.     else if ((hParentMenu = ::GetMenu(m_hWnd)) != NULL)
  1328.     {
  1329.         CWnd* pParent = GetTopLevelParent();
  1330.             // child windows don't have menus -- need to go to the top!
  1331.         if (pParent != NULL &&
  1332.             (hParentMenu = ::GetMenu(pParent->m_hWnd)) != NULL)
  1333.         {
  1334.             int nIndexMax = ::GetMenuItemCount(hParentMenu);
  1335.             for (int nIndex = 0; nIndex < nIndexMax; nIndex++)
  1336.             {
  1337.                 if (::GetSubMenu(hParentMenu, nIndex) == pMenu->m_hMenu)
  1338.                 {
  1339.                     // when popup is found, m_pParentMenu is containing menu
  1340.                     state.m_pParentMenu = CMenu::FromHandle(hParentMenu);
  1341.                     break;
  1342.                 }
  1343.             }
  1344.         }
  1345.     }
  1346.  
  1347.     state.m_nIndexMax = pMenu->GetMenuItemCount();
  1348.     for (state.m_nIndex = 0; state.m_nIndex < state.m_nIndexMax;
  1349.       state.m_nIndex++)
  1350.     {
  1351.         state.m_nID = pMenu->GetMenuItemID(state.m_nIndex);
  1352.         if (state.m_nID == 0)
  1353.             continue; // menu separator or invalid cmd - ignore it
  1354.  
  1355.         ASSERT(state.m_pOther == NULL);
  1356.         ASSERT(state.m_pMenu != NULL);
  1357.         if (state.m_nID == (UINT)-1)
  1358.         {
  1359.             // possibly a popup menu, route to first item of that popup
  1360.             state.m_pSubMenu = pMenu->GetSubMenu(state.m_nIndex);
  1361.             if (state.m_pSubMenu == NULL ||
  1362.                 (state.m_nID = state.m_pSubMenu->GetMenuItemID(0)) == 0 ||
  1363.                 state.m_nID == (UINT)-1)
  1364.             {
  1365.                 continue;       // first item of popup can't be routed to
  1366.             }
  1367.             state.DoUpdate(this, FALSE);    // popups are never auto disabled
  1368.         }
  1369.         else
  1370.         {
  1371.             // normal menu item
  1372.             // Auto enable/disable if frame window has 'm_bAutoMenuEnable'
  1373.             //    set and command is _not_ a system command.
  1374.             state.m_pSubMenu = NULL;
  1375.             state.DoUpdate(this, m_bAutoMenuEnable && state.m_nID < 0xF000);
  1376.         }
  1377.  
  1378.         // adjust for menu deletions and additions
  1379.         UINT nCount = pMenu->GetMenuItemCount();
  1380.         if (nCount < state.m_nIndexMax)
  1381.         {
  1382.             state.m_nIndex -= (state.m_nIndexMax - nCount);
  1383.             while (state.m_nIndex < nCount &&
  1384.                 pMenu->GetMenuItemID(state.m_nIndex) == state.m_nID)
  1385.             {
  1386.                 state.m_nIndex++;
  1387.             }
  1388.         }
  1389.         state.m_nIndexMax = nCount;
  1390.     }
  1391. }
  1392.  
  1393. void CFrameWnd::OnMenuSelect(UINT nItemID, UINT nFlags, HMENU hSysMenu)
  1394. {
  1395.     CFrameWnd* pFrameWnd = GetTopLevelFrame();
  1396.     ASSERT_VALID(pFrameWnd);
  1397.  
  1398. #ifndef _AFX_NO_OLE_SUPPORT
  1399.     // allow hook to consume message
  1400.     if (m_pNotifyHook != NULL)
  1401.     {
  1402. #ifdef _AFXDLL
  1403.         ASSERT(m_pModuleState != NULL);
  1404.         if (m_pModuleState->m_dwVersion >= 0x423)
  1405. #endif
  1406.             if (m_pNotifyHook->OnMenuSelect(nItemID, nFlags, hSysMenu))
  1407.                 return;
  1408.     }
  1409. #endif
  1410.  
  1411.     // set the tracking state (update on idle)
  1412.     if (nFlags == 0xFFFF)
  1413.     {
  1414.         // cancel menu operation (go back to idle now)
  1415.         m_nFlags &= ~WF_NOPOPMSG;
  1416.         if (!pFrameWnd->m_bHelpMode)
  1417.             m_nIDTracking = AFX_IDS_IDLEMESSAGE;
  1418.         else
  1419.             m_nIDTracking = AFX_IDS_HELPMODEMESSAGE;
  1420.         SendMessage(WM_SETMESSAGESTRING, (WPARAM)m_nIDTracking);
  1421.         ASSERT(m_nIDTracking == m_nIDLastMessage);
  1422.  
  1423.         // update right away
  1424.         CWnd* pWnd = GetMessageBar();
  1425.         if (pWnd != NULL)
  1426.             pWnd->UpdateWindow();
  1427.     }
  1428.     else
  1429.     {
  1430.         if (nItemID == 0 || nFlags & (MF_SEPARATOR|MF_POPUP))
  1431.         {
  1432.             // nothing should be displayed
  1433.             m_nIDTracking = 0;
  1434.         }
  1435.         else if (nItemID >= 0xF000 && nItemID < 0xF1F0) // max of 31 SC_s
  1436.         {
  1437.             // special strings table entries for system commands
  1438.             m_nIDTracking = ID_COMMAND_FROM_SC(nItemID);
  1439.             ASSERT(m_nIDTracking >= AFX_IDS_SCFIRST &&
  1440.                 m_nIDTracking < AFX_IDS_SCFIRST + 31);
  1441.         }
  1442.         else if (nItemID >= AFX_IDM_FIRST_MDICHILD)
  1443.         {
  1444.             // all MDI Child windows map to the same help id
  1445.             m_nIDTracking = AFX_IDS_MDICHILD;
  1446.         }
  1447.         else
  1448.         {
  1449.             // track on idle
  1450.             m_nIDTracking = nItemID;
  1451.         }
  1452.         pFrameWnd->m_nFlags |= WF_NOPOPMSG;
  1453.     }
  1454.  
  1455.     // when running in-place, it is necessary to cause a message to
  1456.     //  be pumped through the queue.
  1457.     if (m_nIDTracking != m_nIDLastMessage && GetParent() != NULL)
  1458.         PostMessage(WM_KICKIDLE);
  1459. }
  1460.  
  1461. void CFrameWnd::GetMessageString(UINT nID, CString& rMessage) const
  1462. {
  1463.     // load appropriate string
  1464.     LPTSTR lpsz = rMessage.GetBuffer(255);
  1465.     if (AfxLoadString(nID, lpsz) != 0)
  1466.     {
  1467.         // first newline terminates actual string
  1468.         lpsz = _tcschr(lpsz, '\n');
  1469.         if (lpsz != NULL)
  1470.             *lpsz = '\0';
  1471.     }
  1472.     else
  1473.     {
  1474.         // not found
  1475.         TRACE1("Warning: no message line prompt for ID 0x%04X.\n", nID);
  1476.     }
  1477.     rMessage.ReleaseBuffer();
  1478. }
  1479.  
  1480. LRESULT CFrameWnd::OnPopMessageString(WPARAM wParam, LPARAM lParam)
  1481. {
  1482.     if (m_nFlags & WF_NOPOPMSG)
  1483.         return 0;
  1484.  
  1485.     return SendMessage(WM_SETMESSAGESTRING, wParam, lParam);
  1486. }
  1487.  
  1488. LRESULT CFrameWnd::OnSetMessageString(WPARAM wParam, LPARAM lParam)
  1489. {
  1490.     UINT nIDLast = m_nIDLastMessage;
  1491.     m_nFlags &= ~WF_NOPOPMSG;
  1492.  
  1493.     CWnd* pMessageBar = GetMessageBar();
  1494.     if (pMessageBar != NULL)
  1495.     {
  1496.         LPCTSTR lpsz = NULL;
  1497.         CString strMessage;
  1498.  
  1499.         // set the message bar text
  1500.         if (lParam != 0)
  1501.         {
  1502.             ASSERT(wParam == 0);    // can't have both an ID and a string
  1503.             lpsz = (LPCTSTR)lParam; // set an explicit string
  1504.         }
  1505.         else if (wParam != 0)
  1506.         {
  1507.             // map SC_CLOSE to PREVIEW_CLOSE when in print preview mode
  1508.             if (wParam == AFX_IDS_SCCLOSE && m_lpfnCloseProc != NULL)
  1509.                 wParam = AFX_IDS_PREVIEW_CLOSE;
  1510.  
  1511.             // get message associated with the ID indicated by wParam
  1512.             GetMessageString(wParam, strMessage);
  1513.             lpsz = strMessage;
  1514.         }
  1515.         pMessageBar->SetWindowText(lpsz);
  1516.  
  1517.         // update owner of the bar in terms of last message selected
  1518.         CFrameWnd* pFrameWnd = pMessageBar->GetParentFrame();
  1519.         if (pFrameWnd != NULL)
  1520.         {
  1521.             pFrameWnd->m_nIDLastMessage = (UINT)wParam;
  1522.             pFrameWnd->m_nIDTracking = (UINT)wParam;
  1523.         }
  1524.     }
  1525.  
  1526.     m_nIDLastMessage = (UINT)wParam;    // new ID (or 0)
  1527.     m_nIDTracking = (UINT)wParam;       // so F1 on toolbar buttons work
  1528.     return nIDLast;
  1529. }
  1530.  
  1531. LRESULT CFrameWnd::OnHelpPromptAddr(WPARAM, LPARAM)
  1532. {
  1533.     return (LRESULT)&m_dwPromptContext;
  1534. }
  1535.  
  1536. CWnd* CFrameWnd::GetMessageBar()
  1537. {
  1538.     return GetDescendantWindow(AFX_IDW_STATUS_BAR, TRUE);
  1539. }
  1540.  
  1541. void CFrameWnd::OnEnterIdle(UINT nWhy, CWnd* pWho)
  1542. {
  1543.     CWnd::OnEnterIdle(nWhy, pWho);
  1544.  
  1545.     if (nWhy != MSGF_MENU || m_nIDTracking == m_nIDLastMessage)
  1546.         return;
  1547.  
  1548.     SetMessageText(m_nIDTracking);
  1549.     ASSERT(m_nIDTracking == m_nIDLastMessage);
  1550. }
  1551.  
  1552. void CFrameWnd::SetMessageText(LPCTSTR lpszText)
  1553. {
  1554.     SendMessage(WM_SETMESSAGESTRING, 0, (LPARAM)lpszText);
  1555. }
  1556.  
  1557. void CFrameWnd::SetMessageText(UINT nID)
  1558. {
  1559.     SendMessage(WM_SETMESSAGESTRING, (WPARAM)nID);
  1560. }
  1561.  
  1562. /////////////////////////////////////////////////////////////////////////////
  1563. // CFrameWnd standard control bar management
  1564.  
  1565. void CFrameWnd::DestroyDockBars()
  1566. {
  1567.     // create a list of all the dock bars
  1568.     // this is necessary because m_listControlBars will change
  1569.     // as the dock bars and floating frames are destroyed
  1570.     CPtrList listDockBars;
  1571.     POSITION pos = m_listControlBars.GetHeadPosition();
  1572.     while (pos != NULL)
  1573.     {
  1574.         CDockBar* pDockBar = (CDockBar*)m_listControlBars.GetNext(pos);
  1575.         ASSERT(pDockBar != NULL);
  1576.         if (pDockBar->IsDockBar())
  1577.             listDockBars.AddTail(pDockBar);
  1578.     }
  1579.     pos = listDockBars.GetHeadPosition();
  1580.     while (pos != NULL)
  1581.     {
  1582.         CDockBar* pDockBar = (CDockBar*)listDockBars.GetNext(pos);
  1583.         if (pDockBar->m_bFloating)
  1584.         {
  1585.             CFrameWnd* pFrameWnd = pDockBar->GetParentFrame();
  1586.             ASSERT_VALID(pFrameWnd);
  1587.             pFrameWnd->DestroyWindow();
  1588.         }
  1589.         else
  1590.             pDockBar->DestroyWindow();
  1591.     }
  1592. }
  1593.  
  1594. CControlBar* CFrameWnd::GetControlBar(UINT nID)
  1595. {
  1596.     if (nID == 0)
  1597.         return NULL;
  1598.     POSITION pos = m_listControlBars.GetHeadPosition();
  1599.     while (pos != NULL)
  1600.     {
  1601.         CControlBar* pBar = (CControlBar*)m_listControlBars.GetNext(pos);
  1602.         ASSERT(pBar != NULL);
  1603.         if (_AfxGetDlgCtrlID(pBar->m_hWnd) == nID)
  1604.         {
  1605.             ASSERT_KINDOF(CControlBar, pBar);
  1606.             return pBar;
  1607.         }
  1608.     }
  1609.     return NULL;
  1610. }
  1611.  
  1612. void CFrameWnd::OnUpdateControlBarMenu(CCmdUI* pCmdUI)
  1613. {
  1614.     ASSERT(ID_VIEW_STATUS_BAR == AFX_IDW_STATUS_BAR);
  1615.     ASSERT(ID_VIEW_TOOLBAR == AFX_IDW_TOOLBAR);
  1616.     ASSERT(ID_VIEW_REBAR == AFX_IDW_REBAR);
  1617.  
  1618.     CControlBar* pBar = GetControlBar(pCmdUI->m_nID);
  1619.     if (pBar != NULL)
  1620.     {
  1621.         pCmdUI->SetCheck((pBar->GetStyle() & WS_VISIBLE) != 0);
  1622.         return;
  1623.     }
  1624.     pCmdUI->ContinueRouting();
  1625. }
  1626.  
  1627. BOOL CFrameWnd::OnBarCheck(UINT nID)
  1628. {
  1629.     ASSERT(ID_VIEW_STATUS_BAR == AFX_IDW_STATUS_BAR);
  1630.     ASSERT(ID_VIEW_TOOLBAR == AFX_IDW_TOOLBAR);
  1631.     ASSERT(ID_VIEW_REBAR == AFX_IDW_REBAR);
  1632.  
  1633.     CControlBar* pBar = GetControlBar(nID);
  1634.     if (pBar != NULL)
  1635.     {
  1636.         ShowControlBar(pBar, (pBar->GetStyle() & WS_VISIBLE) == 0, FALSE);
  1637.         return TRUE;
  1638.     }
  1639.     return FALSE;
  1640. }
  1641.  
  1642. BOOL CFrameWnd::OnToolTipText(UINT, NMHDR* pNMHDR, LRESULT* pResult)
  1643. {
  1644.     ASSERT(pNMHDR->code == TTN_NEEDTEXTA || pNMHDR->code == TTN_NEEDTEXTW);
  1645.  
  1646.     // need to handle both ANSI and UNICODE versions of the message
  1647.     TOOLTIPTEXTA* pTTTA = (TOOLTIPTEXTA*)pNMHDR;
  1648.     TOOLTIPTEXTW* pTTTW = (TOOLTIPTEXTW*)pNMHDR;
  1649.     TCHAR szFullText[256];
  1650.     CString strTipText;
  1651.     UINT nID = pNMHDR->idFrom;
  1652.     if (pNMHDR->code == TTN_NEEDTEXTA && (pTTTA->uFlags & TTF_IDISHWND) ||
  1653.         pNMHDR->code == TTN_NEEDTEXTW && (pTTTW->uFlags & TTF_IDISHWND))
  1654.     {
  1655.         // idFrom is actually the HWND of the tool
  1656.         nID = _AfxGetDlgCtrlID((HWND)nID);
  1657.     }
  1658.  
  1659.     if (nID != 0) // will be zero on a separator
  1660.     {
  1661.         // don't handle the message if no string resource found
  1662.         if (AfxLoadString(nID, szFullText) == 0)
  1663.             return FALSE;
  1664.  
  1665.         // this is the command id, not the button index
  1666.         AfxExtractSubString(strTipText, szFullText, 1, '\n');
  1667.     }
  1668. #ifndef _UNICODE
  1669.     if (pNMHDR->code == TTN_NEEDTEXTA)
  1670.         lstrcpyn(pTTTA->szText, strTipText, _countof(pTTTA->szText));
  1671.     else
  1672.         _mbstowcsz(pTTTW->szText, strTipText, _countof(pTTTW->szText));
  1673. #else
  1674.     if (pNMHDR->code == TTN_NEEDTEXTA)
  1675.         _wcstombsz(pTTTA->szText, strTipText, _countof(pTTTA->szText));
  1676.     else
  1677.         lstrcpyn(pTTTW->szText, strTipText, _countof(pTTTW->szText));
  1678. #endif
  1679.     *pResult = 0;
  1680.  
  1681.     // bring the tooltip window above other popup windows
  1682.     ::SetWindowPos(pNMHDR->hwndFrom, HWND_TOP, 0, 0, 0, 0,
  1683.         SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOOWNERZORDER);
  1684.  
  1685.     return TRUE;    // message was handled
  1686. }
  1687.  
  1688. /////////////////////////////////////////////////////////////////////////////
  1689. // Support for standard status bar
  1690.  
  1691. void CFrameWnd::OnUpdateKeyIndicator(CCmdUI* pCmdUI)
  1692. {
  1693.     UINT nVK;
  1694.     UINT flag = 0x0001;
  1695.  
  1696.     switch (pCmdUI->m_nID)
  1697.     {
  1698.     case ID_INDICATOR_CAPS:
  1699.         nVK = VK_CAPITAL;
  1700.         break;
  1701.  
  1702.     case ID_INDICATOR_NUM:
  1703.         nVK = VK_NUMLOCK;
  1704.         break;
  1705.  
  1706.     case ID_INDICATOR_SCRL:
  1707.         nVK = VK_SCROLL;
  1708.         break;
  1709.  
  1710.     case ID_INDICATOR_KANA:
  1711.         nVK = VK_KANA;
  1712.         // WINBUG: Special case for Windows 3.x.  The wrong bit was toggled
  1713.         // in those systems so this must be special cased.  This is fixed
  1714.         // on systems whose version is 4.x or greater.
  1715.         if (!afxData.bWin4)
  1716.             flag = 0x8000;
  1717.         break;
  1718.  
  1719.     default:
  1720.         TRACE1("Warning: OnUpdateKeyIndicator - unknown indicator 0x%04X.\n",
  1721.             pCmdUI->m_nID);
  1722.         pCmdUI->ContinueRouting();
  1723.         return; // not for us
  1724.     }
  1725.  
  1726.     pCmdUI->Enable(::GetKeyState(nVK) & flag);
  1727.         // enable static text based on toggled key state
  1728.     ASSERT(pCmdUI->m_bEnableChanged);
  1729. }
  1730.  
  1731. void CFrameWnd::OnUpdateContextHelp(CCmdUI* pCmdUI)
  1732. {
  1733.     if (AfxGetMainWnd() == this)
  1734.         pCmdUI->SetCheck(!!m_bHelpMode);
  1735.     else
  1736.         pCmdUI->ContinueRouting();
  1737. }
  1738.  
  1739. /////////////////////////////////////////////////////////////////////////////
  1740. // Setting title of frame window - UISG standard
  1741.  
  1742. void CFrameWnd::OnUpdateFrameTitle(BOOL bAddToTitle)
  1743. {
  1744.     if ((GetStyle() & FWS_ADDTOTITLE) == 0)
  1745.         return;     // leave it alone!
  1746.  
  1747. #ifndef _AFX_NO_OLE_SUPPORT
  1748.     // allow hook to set the title (used for OLE support)
  1749.     if (m_pNotifyHook != NULL && m_pNotifyHook->OnUpdateFrameTitle())
  1750.         return;
  1751. #endif
  1752.  
  1753.     CDocument* pDocument = GetActiveDocument();
  1754.     if (bAddToTitle && pDocument != NULL)
  1755.         UpdateFrameTitleForDocument(pDocument->GetTitle());
  1756.     else
  1757.         UpdateFrameTitleForDocument(NULL);
  1758. }
  1759.  
  1760. void CFrameWnd::UpdateFrameTitleForDocument(LPCTSTR lpszDocName)
  1761. {
  1762.     // copy first part of title loaded at time of frame creation
  1763.     TCHAR szText[256+_MAX_PATH];
  1764.  
  1765.     if (GetStyle() & FWS_PREFIXTITLE)
  1766.     {
  1767.         szText[0] = '\0';   // start with nothing
  1768.  
  1769.         // get name of currently active view
  1770.         if (lpszDocName != NULL)
  1771.         {
  1772.             lstrcpy(szText, lpszDocName);
  1773.             // add current window # if needed
  1774.             if (m_nWindow > 0)
  1775.                 wsprintf(szText + lstrlen(szText), _T(":%d"), m_nWindow);
  1776.             lstrcat(szText, _T(" - "));
  1777.         }
  1778.         lstrcat(szText, m_strTitle);
  1779.     }
  1780.     else
  1781.     {
  1782.         // get name of currently active view
  1783.         lstrcpy(szText, m_strTitle);
  1784.         if (lpszDocName != NULL)
  1785.         {
  1786.             lstrcat(szText, _T(" - "));
  1787.             lstrcat(szText, lpszDocName);
  1788.             // add current window # if needed
  1789.             if (m_nWindow > 0)
  1790.                 wsprintf(szText + lstrlen(szText), _T(":%d"), m_nWindow);
  1791.         }
  1792.     }
  1793.  
  1794.     // set title if changed, but don't remove completely
  1795.     // Note: will be excessive for MDI Frame with maximized child
  1796.     AfxSetWindowText(m_hWnd, szText);
  1797. }
  1798.  
  1799. /////////////////////////////////////////////////////////////////////////////
  1800.  
  1801. void CFrameWnd::OnSetPreviewMode(BOOL bPreview, CPrintPreviewState* pState)
  1802. {
  1803.     // default implementation changes control bars, menu and main pane window
  1804.  
  1805. #ifndef _AFX_NO_OLE_SUPPORT
  1806.     CFrameWnd* pActiveFrame = GetActiveFrame();
  1807.     ASSERT_VALID(pActiveFrame);
  1808.     if (bPreview && pActiveFrame->m_pNotifyHook != NULL)
  1809.         pActiveFrame->m_pNotifyHook->OnDocActivate(FALSE);
  1810. #endif
  1811.  
  1812.     // Set visibility of standard ControlBars (only the first 32)
  1813.     DWORD dwOldStates = 0;
  1814.     POSITION pos = m_listControlBars.GetHeadPosition();
  1815.     while (pos != NULL)
  1816.     {
  1817.         CControlBar* pBar = (CControlBar*)m_listControlBars.GetNext(pos);
  1818.         ASSERT_VALID(pBar);
  1819.         UINT nID = _AfxGetDlgCtrlID(pBar->m_hWnd);
  1820.         if (nID >= AFX_IDW_CONTROLBAR_FIRST && nID <= AFX_IDW_CONTROLBAR_FIRST+31)
  1821.         {
  1822.             DWORD dwMask = 1L << (nID - AFX_IDW_CONTROLBAR_FIRST);
  1823.             if (pBar->IsVisible())
  1824.                 dwOldStates |= dwMask;      // save if previously visible
  1825.             if (!pBar->IsDockBar() || nID != AFX_IDW_DOCKBAR_FLOAT)
  1826.                 ShowControlBar(pBar, (pState->dwStates & dwMask), TRUE);
  1827.         }
  1828.     }
  1829.     pState->dwStates = dwOldStates; // save for restore
  1830.  
  1831.     if (bPreview)
  1832.     {
  1833.         // Entering Print Preview
  1834.         ASSERT(m_lpfnCloseProc == NULL);    // no chaining
  1835.         m_lpfnCloseProc = pState->lpfnCloseProc;
  1836.  
  1837.         // show any modeless dialogs, popup windows, float tools, etc
  1838.         ShowOwnedWindows(FALSE);
  1839.  
  1840.         // Hide the main pane
  1841.         HWND hWnd = ::GetDlgItem(m_hWnd, pState->nIDMainPane);
  1842.         ASSERT(hWnd != NULL);       // must be one that we are hiding!
  1843.         ::ShowWindow(hWnd, SW_HIDE);
  1844.  
  1845.         // Get rid of the menu first (will resize the window)
  1846.         pState->hMenu = ::GetMenu(m_hWnd);
  1847.         if (pState->hMenu != NULL)
  1848.         {
  1849.             // Invalidate before SetMenu since we are going to replace
  1850.             //  the frame's client area anyway
  1851.             Invalidate();
  1852.             SetMenu(NULL);
  1853.             m_nIdleFlags &= ~idleMenu;  // avoid any idle menu processing
  1854.         }
  1855.  
  1856.         // Save the accelerator table and remove it.
  1857.         pState->hAccelTable = m_hAccelTable;
  1858.         m_hAccelTable = NULL;
  1859.         LoadAccelTable(MAKEINTRESOURCE(AFX_IDR_PREVIEW_ACCEL));
  1860.  
  1861.         // Make room for the PreviewView by changing AFX_IDW_PANE_FIRST's ID
  1862.         //  to AFX_IDW_PREVIEW_FIRST
  1863.         if (pState->nIDMainPane != AFX_IDW_PANE_FIRST)
  1864.             hWnd = ::GetDlgItem(m_hWnd, AFX_IDW_PANE_FIRST);
  1865.         if (hWnd != NULL)
  1866.             _AfxSetDlgCtrlID(hWnd, AFX_IDW_PANE_SAVE);
  1867.  
  1868. #ifdef _DEBUG
  1869.         if ((::GetWindowLong(m_hWnd, GWL_STYLE) & (WS_HSCROLL|WS_VSCROLL)) != 0)
  1870.             TRACE0("Warning: scroll bars in frame windows may cause unusual behaviour.\n");
  1871. #endif
  1872.     }
  1873.     else
  1874.     {
  1875.         // Leaving Preview
  1876.         m_lpfnCloseProc = NULL;
  1877.  
  1878.         // shift original AFX_IDW_PANE_FIRST back to its rightful ID
  1879.         HWND hWnd = ::GetDlgItem(m_hWnd, AFX_IDW_PANE_SAVE);
  1880.         if (hWnd != NULL)
  1881.         {
  1882.             HWND hWndTemp = ::GetDlgItem(m_hWnd, AFX_IDW_PANE_FIRST);
  1883.             if (hWndTemp != NULL)
  1884.                 _AfxSetDlgCtrlID(hWndTemp, AFX_IDW_PANE_SAVE);
  1885.             _AfxSetDlgCtrlID(hWnd, AFX_IDW_PANE_FIRST);
  1886.         }
  1887.  
  1888.         // put the menu back in place if it was removed before
  1889.         if (pState->hMenu != NULL)
  1890.         {
  1891.             // Invalidate before SetMenu since we are going to replace
  1892.             //  the frame's client area anyway
  1893.             Invalidate();
  1894.             ::SetMenu(m_hWnd, pState->hMenu);
  1895.         }
  1896.  
  1897.         // recalc layout now, before showing the main pane
  1898. #ifndef _AFX_NO_OLE_SUPPORT
  1899.         if (pActiveFrame->m_pNotifyHook != NULL)
  1900.             pActiveFrame->m_pNotifyHook->OnDocActivate(TRUE);
  1901. #endif
  1902.         RecalcLayout();
  1903.  
  1904.         // now show main pane that was hidden
  1905.         if (pState->nIDMainPane != AFX_IDW_PANE_FIRST)
  1906.             hWnd = ::GetDlgItem(m_hWnd, pState->nIDMainPane);
  1907.         ASSERT(hWnd != NULL);
  1908.         ::ShowWindow(hWnd, SW_SHOW);
  1909.  
  1910.         // Restore the Accelerator table
  1911.         m_hAccelTable = pState->hAccelTable;
  1912.  
  1913.         // show any modeless dialogs, popup windows, float tools, etc
  1914.         ShowOwnedWindows(TRUE);
  1915.     }
  1916. }
  1917.  
  1918. void CFrameWnd::DelayUpdateFrameMenu(HMENU hMenuAlt)
  1919. {
  1920.     m_hMenuAlt = hMenuAlt;
  1921.     m_nIdleFlags |= idleMenu;
  1922. }
  1923.  
  1924. void CFrameWnd::OnIdleUpdateCmdUI()
  1925. {
  1926.     // update menu if necessary
  1927.     if (m_nIdleFlags & idleMenu)
  1928.         OnUpdateFrameMenu(m_hMenuAlt);
  1929.  
  1930.     // update title if necessary
  1931.     if (m_nIdleFlags & idleTitle)
  1932.         OnUpdateFrameTitle(TRUE);
  1933.  
  1934.     // recalc layout if necessary
  1935.     if (m_nIdleFlags & idleLayout)
  1936.     {
  1937.         RecalcLayout(m_nIdleFlags & idleNotify);
  1938.         UpdateWindow();
  1939.     }
  1940.  
  1941.     // set the current message string if necessary
  1942.     if (m_nIDTracking != m_nIDLastMessage)
  1943.     {
  1944.         SetMessageText(m_nIDTracking);
  1945.         ASSERT(m_nIDTracking == m_nIDLastMessage);
  1946.     }
  1947.     m_nIdleFlags = 0;
  1948. }
  1949.  
  1950. CFrameWnd* CFrameWnd::GetActiveFrame()
  1951. {
  1952.     // by default, the active frame is the frame itself (MDI is different)
  1953.     return this;
  1954. }
  1955.  
  1956. void CFrameWnd::RecalcLayout(BOOL bNotify)
  1957. {
  1958.     if (m_bInRecalcLayout)
  1959.         return;
  1960.  
  1961.     m_bInRecalcLayout = TRUE;
  1962.     // clear idle flags for recalc layout if called elsewhere
  1963.     if (m_nIdleFlags & idleNotify)
  1964.         bNotify = TRUE;
  1965.     m_nIdleFlags &= ~(idleLayout|idleNotify);
  1966.  
  1967. #ifndef _AFX_NO_OLE_SUPPORT
  1968.     // call the layout hook -- OLE support uses this hook
  1969.     if (bNotify && m_pNotifyHook != NULL)
  1970.         m_pNotifyHook->OnRecalcLayout();
  1971. #endif
  1972.  
  1973.     // reposition all the child windows (regardless of ID)
  1974.     if (GetStyle() & FWS_SNAPTOBARS)
  1975.     {
  1976.         CRect rect(0, 0, 32767, 32767);
  1977.         RepositionBars(0, 0xffff, AFX_IDW_PANE_FIRST, reposQuery,
  1978.             &rect, &rect, FALSE);
  1979.         RepositionBars(0, 0xffff, AFX_IDW_PANE_FIRST, reposExtra,
  1980.             &m_rectBorder, &rect, TRUE);
  1981.         CalcWindowRect(&rect);
  1982.         SetWindowPos(NULL, 0, 0, rect.Width(), rect.Height(),
  1983.             SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);
  1984.     }
  1985.     else
  1986.         RepositionBars(0, 0xffff, AFX_IDW_PANE_FIRST, reposExtra, &m_rectBorder);
  1987.     m_bInRecalcLayout = FALSE;
  1988. }
  1989.  
  1990. // CFrameWnd implementation of OLE border space negotiation
  1991. BOOL CFrameWnd::NegotiateBorderSpace(UINT nBorderCmd, LPRECT lpRectBorder)
  1992. {
  1993.     CRect border, request;
  1994.  
  1995.     switch (nBorderCmd)
  1996.     {
  1997.     case borderGet:
  1998.         ASSERT(lpRectBorder != NULL);
  1999.         RepositionBars(0, 0xffff, AFX_IDW_PANE_FIRST, reposQuery,
  2000.             lpRectBorder);
  2001.         break;
  2002.  
  2003.     case borderRequest:
  2004.         return TRUE;
  2005.  
  2006.     case borderSet:
  2007.         if (lpRectBorder == NULL)
  2008.         {
  2009.             if (!m_rectBorder.IsRectNull())
  2010.             {
  2011.                 // releasing all border space -- recalc needed
  2012.                 m_rectBorder.SetRectEmpty();
  2013.                 return TRUE;
  2014.             }
  2015.             // original rect is empty & lpRectBorder is NULL, no recalc needed
  2016.             return FALSE;
  2017.         }
  2018.         if (!::EqualRect(m_rectBorder, lpRectBorder))
  2019.         {
  2020.             // the rects are different -- recalc needed
  2021.             m_rectBorder.CopyRect(lpRectBorder);
  2022.             return TRUE;
  2023.         }
  2024.         return FALSE;   // no recalc needed
  2025.  
  2026.     default:
  2027.         ASSERT(FALSE);  // invalid CFrameWnd::BorderCmd
  2028.     }
  2029.  
  2030.     return TRUE;
  2031. }
  2032.  
  2033. void CFrameWnd::OnSize(UINT nType, int cx, int cy)
  2034. {
  2035.     CWnd::OnSize(nType, cx, cy);    // important for MDI Children
  2036.     if (nType != SIZE_MINIMIZED)
  2037.         RecalcLayout();
  2038. }
  2039.  
  2040. BOOL CFrameWnd::OnEraseBkgnd(CDC* pDC)
  2041. {
  2042.     if (m_pViewActive != NULL)
  2043.         return TRUE;        // active view will erase/paint itself
  2044.     // for view-less frame just use the default background fill
  2045.     return CWnd::OnEraseBkgnd(pDC);
  2046. }
  2047.  
  2048. LRESULT CFrameWnd::OnRegisteredMouseWheel(WPARAM wParam, LPARAM lParam)
  2049. {
  2050.     // convert from MSH_MOUSEWHEEL to WM_MOUSEWHEEL
  2051.  
  2052.     WORD keyState = 0;
  2053.     keyState |= (::GetKeyState(VK_CONTROL) < 0) ? MK_CONTROL : 0;
  2054.     keyState |= (::GetKeyState(VK_SHIFT) < 0) ? MK_SHIFT : 0;
  2055.  
  2056.     LRESULT lResult;
  2057.     HWND hwFocus = ::GetFocus();
  2058.     const HWND hwDesktop = ::GetDesktopWindow();
  2059.  
  2060.     if (hwFocus == NULL)
  2061.         lResult = SendMessage(WM_MOUSEWHEEL, (wParam << 16) | keyState, lParam);
  2062.     else
  2063.     {
  2064.         do {
  2065.             lResult = ::SendMessage(hwFocus, WM_MOUSEWHEEL,
  2066.                 (wParam << 16) | keyState, lParam);
  2067.             hwFocus = ::GetParent(hwFocus);
  2068.         }
  2069.         while (lResult == 0 && hwFocus != NULL && hwFocus != hwDesktop);
  2070.     }
  2071.     return lResult;
  2072. }
  2073.  
  2074. void CFrameWnd::ActivateFrame(int nCmdShow)
  2075.     // nCmdShow is the normal show mode this frame should be in
  2076. {
  2077.     // translate default nCmdShow (-1)
  2078.     if (nCmdShow == -1)
  2079.     {
  2080.         if (!IsWindowVisible())
  2081.             nCmdShow = SW_SHOWNORMAL;
  2082.         else if (IsIconic())
  2083.             nCmdShow = SW_RESTORE;
  2084.     }
  2085.  
  2086.     // bring to top before showing
  2087.     BringToTop(nCmdShow);
  2088.  
  2089.     if (nCmdShow != -1)
  2090.     {
  2091.         // show the window as specified
  2092.         ShowWindow(nCmdShow);
  2093.  
  2094.         // and finally, bring to top after showing
  2095.         BringToTop(nCmdShow);
  2096.     }
  2097. }
  2098.  
  2099. void CFrameWnd::BringToTop(int nCmdShow)
  2100. {
  2101.     // place the window on top except for certain nCmdShow
  2102.     if (nCmdShow != SW_HIDE &&
  2103.         nCmdShow != SW_MINIMIZE && nCmdShow != SW_SHOWMINNOACTIVE &&
  2104.         nCmdShow != SW_SHOWNA && nCmdShow != SW_SHOWNOACTIVATE)
  2105.     {
  2106.         // if no last active popup, it will return m_hWnd
  2107.         HWND hWndLastPop = ::GetLastActivePopup(m_hWnd);
  2108.         ::BringWindowToTop(hWndLastPop);
  2109.     }
  2110. }
  2111.  
  2112. /////////////////////////////////////////////////////////////////////////////
  2113. // CFrameWnd Diagnostics
  2114.  
  2115. #ifdef _DEBUG
  2116. void CFrameWnd::AssertValid() const
  2117. {
  2118.     CWnd::AssertValid();
  2119.     if (m_pViewActive != NULL)
  2120.         ASSERT_VALID(m_pViewActive);
  2121. }
  2122.  
  2123. void CFrameWnd::Dump(CDumpContext& dc) const
  2124. {
  2125.     CWnd::Dump(dc);
  2126.  
  2127.     dc << "m_hAccelTable = " << (UINT)m_hAccelTable;
  2128.     dc << "\nm_nWindow = " << m_nWindow;
  2129.     dc << "\nm_nIDHelp = " << m_nIDHelp;
  2130.     dc << "\nm_nIDTracking = " << m_nIDTracking;
  2131.     dc << "\nm_nIDLastMessage = " << m_nIDLastMessage;
  2132.     if (m_pViewActive != NULL)
  2133.         dc << "\nwith active view: " << m_pViewActive;
  2134.     else
  2135.         dc << "\nno active view";
  2136.  
  2137.     dc << "\n";
  2138. }
  2139. #endif //_DEBUG
  2140.  
  2141. /////////////////////////////////////////////////////////////////////////////
  2142. // CControlBar segmentation
  2143.  
  2144. CFrameWnd* CControlBar::GetDockingFrame() const
  2145. {
  2146.     CFrameWnd* pFrameWnd = GetParentFrame();
  2147.     if (pFrameWnd == NULL)
  2148.         pFrameWnd = m_pDockSite;
  2149.  
  2150.     ASSERT(pFrameWnd != NULL);
  2151.     ASSERT_KINDOF(CFrameWnd, pFrameWnd);
  2152.     return pFrameWnd;
  2153. }
  2154.  
  2155. BOOL CControlBar::IsFloating() const
  2156. {
  2157.     if (IsDockBar())
  2158.         return ((CDockBar*)this)->m_bFloating;
  2159.     else
  2160.         return m_pDockBar != NULL && m_pDockBar->m_bFloating;
  2161. }
  2162.  
  2163. #ifdef AFX_INIT_SEG
  2164. #pragma code_seg(AFX_INIT_SEG)
  2165. #endif
  2166.  
  2167. // in this file for IsKindOf library granularity (IsKindOf references these)
  2168. IMPLEMENT_DYNCREATE(CFrameWnd, CWnd)
  2169. IMPLEMENT_DYNAMIC(CView, CWnd)
  2170. IMPLEMENT_DYNAMIC(CControlBar, CWnd)
  2171.  
  2172. /////////////////////////////////////////////////////////////////////////////
  2173.