home *** CD-ROM | disk | FTP | other *** search
/ Supercompiler 1997 / SUPERCOMPILER97.iso / MS_VC.50 / VC / MFC / SRC / WINCORE.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1997-01-07  |  103.0 KB  |  3,850 lines

  1. // This is a part of the Microsoft Foundation Classes C++ library.
  2. // Copyright (C) 1992-1997 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. #ifndef _AFX_NO_OCC_SUPPORT
  13. #include "occimpl.h"
  14. #endif
  15.  
  16. #ifdef AFX_CORE1_SEG
  17. #pragma code_seg(AFX_CORE1_SEG)
  18. #endif
  19.  
  20. #ifdef _DEBUG
  21. #undef THIS_FILE
  22. static char THIS_FILE[] = __FILE__;
  23. #endif
  24.  
  25. #define new DEBUG_NEW
  26.  
  27. /////////////////////////////////////////////////////////////////////////////
  28. // Globals
  29.  
  30. const UINT CWnd::m_nMsgDragList = ::RegisterWindowMessage(DRAGLISTMSGSTRING);
  31.  
  32. // CWnds for setting z-order with SetWindowPos's pWndInsertAfter parameter
  33. const AFX_DATADEF CWnd CWnd::wndTop(HWND_TOP);
  34. const AFX_DATADEF CWnd CWnd::wndBottom(HWND_BOTTOM);
  35. const AFX_DATADEF CWnd CWnd::wndTopMost(HWND_TOPMOST);
  36. const AFX_DATADEF CWnd CWnd::wndNoTopMost(HWND_NOTOPMOST);
  37.  
  38. const TCHAR _afxWnd[] = AFX_WND;
  39. const TCHAR _afxWndControlBar[] = AFX_WNDCONTROLBAR;
  40. const TCHAR _afxWndMDIFrame[] = AFX_WNDMDIFRAME;
  41. const TCHAR _afxWndFrameOrView[] = AFX_WNDFRAMEORVIEW;
  42. const TCHAR _afxWndOleControl[] = AFX_WNDOLECONTROL;
  43.  
  44. // implemented in viewscrl.cpp
  45. extern UINT _AfxGetMouseScrollLines(BOOL bForceFresh = FALSE);
  46.  
  47. /////////////////////////////////////////////////////////////////////////////
  48. // CWnd construction
  49.  
  50. CWnd::CWnd()
  51. {
  52.     AFX_ZERO_INIT_OBJECT(CCmdTarget);
  53.     m_pCtrlSite = NULL;
  54.     m_pCtrlCont = NULL;
  55. }
  56.  
  57. CWnd::CWnd(HWND hWnd)
  58. {
  59.     AFX_ZERO_INIT_OBJECT(CCmdTarget);
  60.     m_hWnd = hWnd;
  61.     m_pCtrlSite = NULL;
  62.     m_pCtrlCont = NULL;
  63. }
  64.  
  65. // Change a window's style
  66.  
  67. static BOOL AFXAPI _AfxModifyStyle(HWND hWnd, int nStyleOffset,
  68.     DWORD dwRemove, DWORD dwAdd, UINT nFlags)
  69. {
  70.     ASSERT(hWnd != NULL);
  71.     DWORD dwStyle = ::GetWindowLong(hWnd, nStyleOffset);
  72.     DWORD dwNewStyle = (dwStyle & ~dwRemove) | dwAdd;
  73.     if (dwStyle == dwNewStyle)
  74.         return FALSE;
  75.  
  76.     ::SetWindowLong(hWnd, nStyleOffset, dwNewStyle);
  77.     if (nFlags != 0)
  78.     {
  79.         ::SetWindowPos(hWnd, NULL, 0, 0, 0, 0,
  80.             SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | nFlags);
  81.     }
  82.     return TRUE;
  83. }
  84.  
  85. BOOL PASCAL
  86. CWnd::ModifyStyle(HWND hWnd, DWORD dwRemove, DWORD dwAdd, UINT nFlags)
  87. {
  88.     return _AfxModifyStyle(hWnd, GWL_STYLE, dwRemove, dwAdd, nFlags);
  89. }
  90.  
  91. BOOL PASCAL
  92. CWnd::ModifyStyleEx(HWND hWnd, DWORD dwRemove, DWORD dwAdd, UINT nFlags)
  93. {
  94.     return _AfxModifyStyle(hWnd, GWL_EXSTYLE, dwRemove, dwAdd, nFlags);
  95. }
  96.  
  97. /////////////////////////////////////////////////////////////////////////////
  98. // Special helpers for certain windows messages
  99.  
  100. static void AFXAPI _AfxPreInitDialog(
  101.     CWnd* pWnd, LPRECT lpRectOld, DWORD* pdwStyleOld)
  102. {
  103.     ASSERT(lpRectOld != NULL);
  104.     ASSERT(pdwStyleOld != NULL);
  105.  
  106.     pWnd->GetWindowRect(lpRectOld);
  107.     *pdwStyleOld = pWnd->GetStyle();
  108. }
  109.  
  110. static void AFXAPI _AfxPostInitDialog(
  111.     CWnd* pWnd, const RECT& rectOld, DWORD dwStyleOld)
  112. {
  113.     // must be hidden to start with
  114.     if (dwStyleOld & WS_VISIBLE)
  115.         return;
  116.  
  117.     // must not be visible after WM_INITDIALOG
  118.     if (pWnd->GetStyle() & (WS_VISIBLE|WS_CHILD))
  119.         return;
  120.  
  121.     // must not move during WM_INITDIALOG
  122.     CRect rect;
  123.     pWnd->GetWindowRect(rect);
  124.     if (rectOld.left != rect.left || rectOld.top != rect.top)
  125.         return;
  126.  
  127.     // must be unowned or owner disabled
  128.     CWnd* pParent = pWnd->GetWindow(GW_OWNER);
  129.     if (pParent != NULL && pParent->IsWindowEnabled())
  130.         return;
  131.  
  132.     if (!pWnd->CheckAutoCenter())
  133.         return;
  134.  
  135.     // center modal dialog boxes/message boxes
  136.     pWnd->CenterWindow();
  137. }
  138.  
  139. static void AFXAPI
  140. _AfxHandleActivate(CWnd* pWnd, WPARAM nState, CWnd* pWndOther)
  141. {
  142.     ASSERT(pWnd != NULL);
  143.  
  144.     // send WM_ACTIVATETOPLEVEL when top-level parents change
  145.     CWnd* pTopLevel;
  146.     if (!(pWnd->GetStyle() & WS_CHILD) &&
  147.         (pTopLevel = pWnd->GetTopLevelParent()) != pWndOther->GetTopLevelParent())
  148.     {
  149.         // lParam points to window getting the WM_ACTIVATE message and
  150.         //  hWndOther from the WM_ACTIVATE.
  151.         HWND hWnd2[2];
  152.         hWnd2[0] = pWnd->m_hWnd;
  153.         hWnd2[1] = pWndOther->GetSafeHwnd();
  154.         // send it...
  155.         pTopLevel->SendMessage(WM_ACTIVATETOPLEVEL, nState, (LPARAM)&hWnd2[0]);
  156.     }
  157. }
  158.  
  159. static BOOL AFXAPI
  160. _AfxHandleSetCursor(CWnd* pWnd, UINT nHitTest, UINT nMsg)
  161. {
  162.     if (nHitTest == HTERROR &&
  163.         (nMsg == WM_LBUTTONDOWN || nMsg == WM_MBUTTONDOWN ||
  164.          nMsg == WM_RBUTTONDOWN))
  165.     {
  166.         // activate the last active window if not active
  167.         CWnd* pLastActive = pWnd->GetTopLevelParent();
  168.         if (pLastActive != NULL)
  169.             pLastActive = pLastActive->GetLastActivePopup();
  170.         if (pLastActive != NULL &&
  171.             pLastActive != CWnd::GetForegroundWindow() &&
  172.             pLastActive->IsWindowEnabled())
  173.         {
  174.             pLastActive->SetForegroundWindow();
  175.             return TRUE;
  176.         }
  177.     }
  178.     return FALSE;
  179. }
  180.  
  181. /////////////////////////////////////////////////////////////////////////////
  182. // Official way to send message to a CWnd
  183.  
  184. LRESULT AFXAPI AfxCallWndProc(CWnd* pWnd, HWND hWnd, UINT nMsg,
  185.     WPARAM wParam = 0, LPARAM lParam = 0)
  186. {
  187.     _AFX_THREAD_STATE* pThreadState = _afxThreadState.GetData();
  188.     MSG oldState = pThreadState->m_lastSentMsg;   // save for nesting
  189.     pThreadState->m_lastSentMsg.hwnd = hWnd;
  190.     pThreadState->m_lastSentMsg.message = nMsg;
  191.     pThreadState->m_lastSentMsg.wParam = wParam;
  192.     pThreadState->m_lastSentMsg.lParam = lParam;
  193.  
  194. #ifdef _DEBUG
  195.     if (afxTraceFlags & traceWinMsg)
  196.         _AfxTraceMsg(_T("WndProc"), &pThreadState->m_lastSentMsg);
  197. #endif
  198.  
  199.     // Catch exceptions thrown outside the scope of a callback
  200.     // in debug builds and warn the user.
  201.     LRESULT lResult;
  202.     TRY
  203.     {
  204. #ifndef _AFX_NO_OCC_SUPPORT
  205.         // special case for WM_DESTROY
  206.         if ((nMsg == WM_DESTROY) && (pWnd->m_pCtrlCont != NULL))
  207.             pWnd->m_pCtrlCont->OnUIActivate(NULL);
  208. #endif
  209.  
  210.         // special case for WM_INITDIALOG
  211.         CRect rectOld;
  212.         DWORD dwStyle;
  213.         if (nMsg == WM_INITDIALOG)
  214.             _AfxPreInitDialog(pWnd, &rectOld, &dwStyle);
  215.  
  216.         // delegate to object's WindowProc
  217.         lResult = pWnd->WindowProc(nMsg, wParam, lParam);
  218.  
  219.         // more special case for WM_INITDIALOG
  220.         if (nMsg == WM_INITDIALOG)
  221.             _AfxPostInitDialog(pWnd, rectOld, dwStyle);
  222.     }
  223.     CATCH_ALL(e)
  224.     {
  225.         lResult = AfxGetThread()->ProcessWndProcException(e, &pThreadState->m_lastSentMsg);
  226.         TRACE1("Warning: Uncaught exception in WindowProc (returning %ld).\n",
  227.             lResult);
  228.         DELETE_EXCEPTION(e);
  229.     }
  230.     END_CATCH_ALL
  231.  
  232.     pThreadState->m_lastSentMsg = oldState;
  233.     return lResult;
  234. }
  235.  
  236. const MSG* PASCAL CWnd::GetCurrentMessage()
  237. {
  238.     // fill in time and position when asked for
  239.     _AFX_THREAD_STATE* pThreadState = _afxThreadState.GetData();
  240.     pThreadState->m_lastSentMsg.time = ::GetMessageTime();
  241.     pThreadState->m_lastSentMsg.pt = CPoint(::GetMessagePos());
  242.     return &pThreadState->m_lastSentMsg;
  243. }
  244.  
  245. LRESULT CWnd::Default()
  246. {
  247.     // call DefWindowProc with the last message
  248.     _AFX_THREAD_STATE* pThreadState = _afxThreadState.GetData();
  249.     return DefWindowProc(pThreadState->m_lastSentMsg.message,
  250.         pThreadState->m_lastSentMsg.wParam, pThreadState->m_lastSentMsg.lParam);
  251. }
  252.  
  253. /////////////////////////////////////////////////////////////////////////////
  254. // Map from HWND to CWnd*
  255.  
  256. static CHandleMap* afxMapHWND(BOOL bCreate = FALSE);
  257.  
  258. static CHandleMap* afxMapHWND(BOOL bCreate)
  259. {
  260.     AFX_MODULE_THREAD_STATE* pState = AfxGetModuleThreadState();
  261.     if (pState->m_pmapHWND == NULL && bCreate)
  262.     {
  263.         BOOL bEnable = AfxEnableMemoryTracking(FALSE);
  264. #ifndef _AFX_PORTABLE
  265.         _PNH pnhOldHandler = AfxSetNewHandler(&AfxCriticalNewHandler);
  266. #endif
  267.         pState->m_pmapHWND = new CHandleMap(RUNTIME_CLASS(CWnd),
  268.             offsetof(CWnd, m_hWnd));
  269.  
  270. #ifndef _AFX_PORTABLE
  271.         AfxSetNewHandler(pnhOldHandler);
  272. #endif
  273.         AfxEnableMemoryTracking(bEnable);
  274.     }
  275.     return pState->m_pmapHWND;
  276. }
  277.  
  278. void PASCAL CWnd::DeleteTempMap()
  279. {
  280.     CHandleMap* pMap = afxMapHWND();
  281.     if (pMap != NULL)
  282.         pMap->DeleteTemp();
  283. }
  284.  
  285. CWnd* PASCAL CWnd::FromHandle(HWND hWnd)
  286. {
  287.     CHandleMap* pMap = afxMapHWND(TRUE); //create map if not exist
  288.     ASSERT(pMap != NULL);
  289.     CWnd* pWnd = (CWnd*)pMap->FromHandle(hWnd);
  290.  
  291. #ifndef _AFX_NO_OCC_SUPPORT
  292.     pWnd->AttachControlSite(pMap);
  293. #endif
  294.  
  295.     ASSERT(pWnd == NULL || pWnd->m_hWnd == hWnd);
  296.     return pWnd;
  297. }
  298.  
  299. CWnd* PASCAL CWnd::FromHandlePermanent(HWND hWnd)
  300. {
  301.     CHandleMap* pMap = afxMapHWND();
  302.     CWnd* pWnd = NULL;
  303.     if (pMap != NULL)
  304.     {
  305.         // only look in the permanent map - does no allocations
  306.         pWnd = (CWnd*)pMap->LookupPermanent(hWnd);
  307.         ASSERT(pWnd == NULL || pWnd->m_hWnd == hWnd);
  308.     }
  309.     return pWnd;
  310. }
  311.  
  312. BOOL CWnd::Attach(HWND hWndNew)
  313. {
  314.     ASSERT(m_hWnd == NULL);     // only attach once, detach on destroy
  315.     ASSERT(FromHandlePermanent(hWndNew) == NULL);
  316.         // must not already be in permanent map
  317.  
  318.     if (hWndNew == NULL)
  319.         return FALSE;
  320.  
  321.     CHandleMap* pMap = afxMapHWND(TRUE); // create map if not exist
  322.     ASSERT(pMap != NULL);
  323.  
  324.     pMap->SetPermanent(m_hWnd = hWndNew, this);
  325.  
  326. #ifndef _AFX_NO_OCC_SUPPORT
  327.     AttachControlSite(pMap);
  328. #endif
  329.  
  330.     return TRUE;
  331. }
  332.  
  333. HWND CWnd::Detach()
  334. {
  335.     HWND hWnd = m_hWnd;
  336.     if (hWnd != NULL)
  337.     {
  338.         CHandleMap* pMap = afxMapHWND(); // don't create if not exist
  339.         if (pMap != NULL)
  340.             pMap->RemoveHandle(m_hWnd);
  341.     m_hWnd = NULL;
  342.     }
  343.  
  344. #ifndef _AFX_NO_OCC_SUPPORT
  345.     m_pCtrlSite = NULL;
  346. #endif
  347.  
  348.     return hWnd;
  349. }
  350.  
  351. void CWnd::PreSubclassWindow()
  352. {
  353.     // no default processing
  354. }
  355.  
  356. /////////////////////////////////////////////////////////////////////////////
  357. // The WndProc for all CWnd's and derived classes
  358.  
  359. LRESULT CALLBACK
  360. AfxWndProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam)
  361. {
  362.     // special message which identifies the window as using AfxWndProc
  363.     if (nMsg == WM_QUERYAFXWNDPROC)
  364.         return 1;
  365.  
  366.     // all other messages route through message map
  367.     CWnd* pWnd = CWnd::FromHandlePermanent(hWnd);
  368.     ASSERT(pWnd != NULL);
  369.     ASSERT(pWnd->m_hWnd == hWnd);
  370.     return AfxCallWndProc(pWnd, hWnd, nMsg, wParam, lParam);
  371. }
  372.  
  373. // always indirectly accessed via AfxGetAfxWndProc
  374. WNDPROC AFXAPI AfxGetAfxWndProc()
  375. {
  376. #ifdef _AFXDLL
  377.     return AfxGetModuleState()->m_pfnAfxWndProc;
  378. #else
  379.     return &AfxWndProc;
  380. #endif
  381. }
  382.  
  383. /////////////////////////////////////////////////////////////////////////////
  384. // Special WndProcs (activation handling & gray dialogs)
  385.  
  386. static const TCHAR szAfxOldWndProc[] = _T("AfxOldWndProc");
  387.  
  388. LRESULT CALLBACK
  389. _AfxActivationWndProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam)
  390. {
  391.     WNDPROC oldWndProc = (WNDPROC)::GetProp(hWnd, szAfxOldWndProc);
  392.     ASSERT(oldWndProc != NULL);
  393.  
  394.     LRESULT lResult = 0;
  395.     TRY
  396.     {
  397.         BOOL bCallDefault = TRUE;
  398.         switch (nMsg)
  399.         {
  400.         case WM_INITDIALOG:
  401.             {
  402.                 DWORD dwStyle;
  403.                 CRect rectOld;
  404.                 CWnd* pWnd = CWnd::FromHandle(hWnd);
  405.                 _AfxPreInitDialog(pWnd, &rectOld, &dwStyle);
  406.                 bCallDefault = FALSE;
  407.                 lResult = CallWindowProc(oldWndProc, hWnd, nMsg, wParam, lParam);
  408.                 _AfxPostInitDialog(pWnd, rectOld, dwStyle);
  409.             }
  410.             break;
  411.  
  412.         case WM_ACTIVATE:
  413.             _AfxHandleActivate(CWnd::FromHandle(hWnd), wParam,
  414.                 CWnd::FromHandle((HWND)lParam));
  415.             break;
  416.  
  417.         case WM_SETCURSOR:
  418.             bCallDefault = !_AfxHandleSetCursor(CWnd::FromHandle(hWnd),
  419.                 (short)LOWORD(lParam), HIWORD(lParam));
  420.             break;
  421.  
  422.         case WM_NCDESTROY:
  423.             SetWindowLong(hWnd, GWL_WNDPROC, (DWORD)oldWndProc);
  424.             RemoveProp(hWnd, szAfxOldWndProc);
  425.             break;
  426.         }
  427.  
  428.         // call original wndproc for default handling
  429.         if (bCallDefault)
  430.             lResult = CallWindowProc(oldWndProc, hWnd, nMsg, wParam, lParam);
  431.     }
  432.     CATCH_ALL(e)
  433.     {
  434.         // handle exception
  435.         MSG msg;
  436.         msg.hwnd = hWnd;
  437.         msg.message = nMsg;
  438.         msg.wParam = wParam;
  439.         msg.lParam = lParam;
  440.         lResult = AfxGetThread()->ProcessWndProcException(e, &msg);
  441.         TRACE1("Warning: Uncaught exception in _AfxActivationWndProc (returning %ld).\n",
  442.             lResult);
  443.         DELETE_EXCEPTION(e);
  444.     }
  445.     END_CATCH_ALL
  446.  
  447.     return lResult;
  448. }
  449.  
  450. LRESULT CALLBACK
  451. _AfxGrayBackgroundWndProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam)
  452. {
  453.     // handle standard gray backgrounds if enabled
  454.     _AFX_WIN_STATE* pWinState = _afxWinState;
  455.     if (pWinState->m_hDlgBkBrush != NULL &&
  456.         (nMsg == WM_CTLCOLORBTN || nMsg == WM_CTLCOLORDLG ||
  457.          nMsg == WM_CTLCOLORSTATIC || nMsg == WM_CTLCOLORSCROLLBAR ||
  458.          nMsg == WM_CTLCOLORLISTBOX) &&
  459.         CWnd::GrayCtlColor((HDC)wParam, (HWND)lParam,
  460.             (UINT)(nMsg - WM_CTLCOLORMSGBOX),
  461.             pWinState->m_hDlgBkBrush, pWinState->m_crDlgTextClr))
  462.     {
  463.         return (LRESULT)pWinState->m_hDlgBkBrush;
  464.     }
  465.  
  466.     // do standard activation related things as well
  467.     return _AfxActivationWndProc(hWnd, nMsg, wParam, lParam);
  468. }
  469.  
  470. /////////////////////////////////////////////////////////////////////////////
  471. // Window creation hooks
  472.  
  473. LRESULT CALLBACK
  474. _AfxCbtFilterHook(int code, WPARAM wParam, LPARAM lParam)
  475. {
  476.     _AFX_THREAD_STATE* pThreadState = _afxThreadState.GetData();
  477.     if (code != HCBT_CREATEWND)
  478.     {
  479.         // wait for HCBT_CREATEWND just pass others on...
  480.         return CallNextHookEx(pThreadState->m_hHookOldCbtFilter, code,
  481.             wParam, lParam);
  482.     }
  483.  
  484.     ASSERT(lParam != NULL);
  485.     LPCREATESTRUCT lpcs = ((LPCBT_CREATEWND)lParam)->lpcs;
  486.     ASSERT(lpcs != NULL);
  487.  
  488.     // this hook exists to set the SendMessage hook on window creations
  489.     //  (but this is only done for MFC windows or non-child windows)
  490.     // the subclassing cannot be done at this point because on Win32s
  491.     //  the window does not have the WNDPROC set yet
  492.     CWnd* pWndInit = pThreadState->m_pWndInit;
  493.     if (pWndInit != NULL || (!(lpcs->style & WS_CHILD) && !afxContextIsDLL))
  494.     {
  495.         ASSERT(wParam != NULL); // should be non-NULL HWND
  496.         HWND hWnd = (HWND)wParam;
  497.         WNDPROC oldWndProc;
  498.         if (pWndInit != NULL)
  499.         {
  500.             // the window should not be in the permanent map at this time
  501.             ASSERT(CWnd::FromHandlePermanent(hWnd) == NULL);
  502.  
  503.             // connect the HWND to pWndInit...
  504.             pWndInit->Attach(hWnd);
  505.             // allow other subclassing to occur first
  506.             pWndInit->PreSubclassWindow();
  507.  
  508.             WNDPROC *pOldWndProc = pWndInit->GetSuperWndProcAddr();
  509.             ASSERT(pOldWndProc != NULL);
  510.  
  511. #ifndef _MAC
  512.             _AFX_CTL3D_STATE* pCtl3dState;
  513.             DWORD dwFlags;
  514.             if (!afxData.bWin4 && !afxContextIsDLL &&
  515.                 (pCtl3dState = _afxCtl3dState.GetDataNA()) != NULL &&
  516.                 pCtl3dState->m_pfnSubclassDlgEx != NULL &&
  517.                 (dwFlags = AfxCallWndProc(pWndInit, hWnd, WM_QUERY3DCONTROLS)) != 0)
  518.             {
  519.                 // was the class registered with AfxWndProc?
  520.                 WNDPROC afxWndProc = AfxGetAfxWndProc();
  521.                 BOOL bAfxWndProc = ((WNDPROC)
  522.                     GetWindowLong(hWnd, GWL_WNDPROC) == afxWndProc);
  523.  
  524.                 pCtl3dState->m_pfnSubclassDlgEx(hWnd, dwFlags);
  525.  
  526.                 // subclass the window if not already wired to AfxWndProc
  527.                 if (!bAfxWndProc)
  528.                 {
  529.                     // subclass the window with standard AfxWndProc
  530.                     oldWndProc = (WNDPROC)SetWindowLong(hWnd, GWL_WNDPROC,
  531.                         (DWORD)afxWndProc);
  532.                     ASSERT(oldWndProc != NULL);
  533.                     *pOldWndProc = oldWndProc;
  534.                 }
  535.             }
  536.             else
  537. #endif
  538.             {
  539.                 // subclass the window with standard AfxWndProc
  540.                 WNDPROC afxWndProc = AfxGetAfxWndProc();
  541.                 oldWndProc = (WNDPROC)SetWindowLong(hWnd, GWL_WNDPROC,
  542.                     (DWORD)afxWndProc);
  543.                 ASSERT(oldWndProc != NULL);
  544.                 if (oldWndProc != afxWndProc)
  545.                     *pOldWndProc = oldWndProc;
  546.             }
  547.             pThreadState->m_pWndInit = NULL;
  548.         }
  549.         else
  550.         {
  551.             ASSERT(!afxContextIsDLL);   // should never get here
  552.  
  553.             // subclass the window with the proc which does gray backgrounds
  554.             oldWndProc = (WNDPROC)GetWindowLong(hWnd, GWL_WNDPROC);
  555.             if (oldWndProc != NULL)
  556.             {
  557.                 ASSERT(GetProp(hWnd, szAfxOldWndProc) == NULL);
  558.                 SetProp(hWnd, szAfxOldWndProc, oldWndProc);
  559.                 if ((WNDPROC)GetProp(hWnd, szAfxOldWndProc) == oldWndProc)
  560.                 {
  561.                     SetWindowLong(hWnd, GWL_WNDPROC,
  562.                         (DWORD)(pThreadState->m_bDlgCreate ?
  563.                             _AfxGrayBackgroundWndProc : _AfxActivationWndProc));
  564.                     ASSERT(oldWndProc != NULL);
  565.                 }
  566.             }
  567.         }
  568.     }
  569.  
  570.     LRESULT lResult = CallNextHookEx(pThreadState->m_hHookOldCbtFilter, code,
  571.         wParam, lParam);
  572.  
  573. #ifndef _AFXDLL
  574.     if (afxContextIsDLL)
  575.     {
  576.         ::UnhookWindowsHookEx(pThreadState->m_hHookOldCbtFilter);
  577.         pThreadState->m_hHookOldCbtFilter = NULL;
  578.     }
  579. #endif
  580.     return lResult;
  581. }
  582.  
  583. void AFXAPI AfxHookWindowCreate(CWnd* pWnd)
  584. {
  585.     _AFX_THREAD_STATE* pThreadState = _afxThreadState.GetData();
  586.     if (pThreadState->m_pWndInit == pWnd)
  587.         return;
  588.  
  589.     if (pThreadState->m_hHookOldCbtFilter == NULL)
  590.     {
  591.         pThreadState->m_hHookOldCbtFilter = ::SetWindowsHookEx(WH_CBT,
  592.             _AfxCbtFilterHook, NULL, ::GetCurrentThreadId());
  593.         if (pThreadState->m_hHookOldCbtFilter == NULL)
  594.             AfxThrowMemoryException();
  595.     }
  596.     ASSERT(pThreadState->m_hHookOldCbtFilter != NULL);
  597.     ASSERT(pWnd != NULL);
  598.     ASSERT(pWnd->m_hWnd == NULL);   // only do once
  599.  
  600.     ASSERT(pThreadState->m_pWndInit == NULL);   // hook not already in progress
  601.     pThreadState->m_pWndInit = pWnd;
  602. }
  603.  
  604. BOOL AFXAPI AfxUnhookWindowCreate()
  605. {
  606.     _AFX_THREAD_STATE* pThreadState = _afxThreadState.GetData();
  607. #ifndef _AFXDLL
  608.     if (afxContextIsDLL && pThreadState->m_hHookOldCbtFilter != NULL)
  609.     {
  610.         ::UnhookWindowsHookEx(pThreadState->m_hHookOldCbtFilter);
  611.         pThreadState->m_hHookOldCbtFilter = NULL;
  612.     }
  613. #endif
  614.     if (pThreadState->m_pWndInit != NULL)
  615.     {
  616.         pThreadState->m_pWndInit = NULL;
  617.         return FALSE;   // was not successfully hooked
  618.     }
  619.     return TRUE;
  620. }
  621.  
  622. /////////////////////////////////////////////////////////////////////////////
  623. // CWnd creation
  624.  
  625. BOOL CWnd::CreateEx(DWORD dwExStyle, LPCTSTR lpszClassName,
  626.         LPCTSTR lpszWindowName, DWORD dwStyle,
  627.         const RECT& rect, CWnd* pParentWnd, UINT nID,
  628.         LPVOID lpParam /* = NULL */)
  629. {
  630.     return CreateEx(dwExStyle, lpszClassName, lpszWindowName, dwStyle,
  631.         rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
  632.         (pParentWnd != NULL) ? pParentWnd->GetSafeHwnd() : NULL,
  633.         (HMENU) nID, lpParam);
  634. }
  635.  
  636. BOOL CWnd::CreateEx(DWORD dwExStyle, LPCTSTR lpszClassName,
  637.     LPCTSTR lpszWindowName, DWORD dwStyle,
  638.     int x, int y, int nWidth, int nHeight,
  639.     HWND hWndParent, HMENU nIDorHMenu, LPVOID lpParam)
  640. {
  641.     // allow modification of several common create parameters
  642.     CREATESTRUCT cs;
  643.     cs.dwExStyle = dwExStyle;
  644.     cs.lpszClass = lpszClassName;
  645.     cs.lpszName = lpszWindowName;
  646.     cs.style = dwStyle;
  647.     cs.x = x;
  648.     cs.y = y;
  649.     cs.cx = nWidth;
  650.     cs.cy = nHeight;
  651.     cs.hwndParent = hWndParent;
  652.     cs.hMenu = nIDorHMenu;
  653.     cs.hInstance = AfxGetInstanceHandle();
  654.     cs.lpCreateParams = lpParam;
  655.  
  656.     if (!PreCreateWindow(cs))
  657.     {
  658.         PostNcDestroy();
  659.         return FALSE;
  660.     }
  661.  
  662.     AfxHookWindowCreate(this);
  663.     HWND hWnd = ::CreateWindowEx(cs.dwExStyle, cs.lpszClass,
  664.             cs.lpszName, cs.style, cs.x, cs.y, cs.cx, cs.cy,
  665.             cs.hwndParent, cs.hMenu, cs.hInstance, cs.lpCreateParams);
  666.  
  667. #ifdef _DEBUG
  668.     if (hWnd == NULL)
  669.     {
  670.         TRACE1("Warning: Window creation failed: GetLastError returns 0x%8.8X\n",
  671.             GetLastError());
  672.     }
  673. #endif
  674.  
  675.     if (!AfxUnhookWindowCreate())
  676.         PostNcDestroy();        // cleanup if CreateWindowEx fails too soon
  677.  
  678.     if (hWnd == NULL)
  679.         return FALSE;
  680.     ASSERT(hWnd == m_hWnd); // should have been set in send msg hook
  681.     return TRUE;
  682. }
  683.  
  684. // for child windows
  685. BOOL CWnd::PreCreateWindow(CREATESTRUCT& cs)
  686. {
  687.     if (cs.lpszClass == NULL)
  688.     {
  689.         // make sure the default window class is registered
  690.         if (!AfxDeferRegisterClass(AFX_WND_REG))
  691.             return FALSE;
  692.  
  693.         // no WNDCLASS provided - use child window default
  694.         ASSERT(cs.style & WS_CHILD);
  695.         cs.lpszClass = _afxWnd;
  696.     }
  697.     return TRUE;
  698. }
  699.  
  700. BOOL CWnd::Create(LPCTSTR lpszClassName,
  701.     LPCTSTR lpszWindowName, DWORD dwStyle,
  702.     const RECT& rect,
  703.     CWnd* pParentWnd, UINT nID,
  704.     CCreateContext* pContext)
  705. {
  706.     // can't use for desktop or pop-up windows (use CreateEx instead)
  707.     ASSERT(pParentWnd != NULL);
  708.     ASSERT((dwStyle & WS_POPUP) == 0);
  709.  
  710.     return CreateEx(0, lpszClassName, lpszWindowName,
  711.         dwStyle | WS_CHILD,
  712.         rect.left, rect.top,
  713.         rect.right - rect.left, rect.bottom - rect.top,
  714.         pParentWnd->GetSafeHwnd(), (HMENU)nID, (LPVOID)pContext);
  715. }
  716.  
  717. CWnd::~CWnd()
  718. {
  719.     if (m_hWnd != NULL &&
  720.         this != (CWnd*)&wndTop && this != (CWnd*)&wndBottom &&
  721.         this != (CWnd*)&wndTopMost && this != (CWnd*)&wndNoTopMost)
  722.     {
  723.         TRACE(_T("Warning: calling DestroyWindow in CWnd::~CWnd; ")
  724.            _T("OnDestroy or PostNcDestroy in derived class will not be called.\n"));
  725.         DestroyWindow();
  726.     }
  727.  
  728. #ifndef _AFX_NO_OCC_SUPPORT
  729.     // cleanup control container,
  730.     // including destroying controls
  731.  
  732.     delete m_pCtrlCont;
  733.  
  734.     // cleanup control site
  735.     if (m_pCtrlSite != NULL && m_pCtrlSite->m_pWndCtrl == this)
  736.         m_pCtrlSite->m_pWndCtrl = NULL;
  737. #endif
  738. }
  739.  
  740. void CWnd::OnDestroy()
  741. {
  742. #ifndef _AFX_NO_OCC_SUPPORT
  743.     // cleanup control container
  744.     delete m_pCtrlCont;
  745.     m_pCtrlCont = NULL;
  746. #endif
  747.     Default();
  748. }
  749.  
  750. // WM_NCDESTROY is the absolute LAST message sent.
  751. void CWnd::OnNcDestroy()
  752. {
  753.     // cleanup main and active windows
  754.     CWinThread* pThread = AfxGetThread();
  755.     if (pThread != NULL)
  756.     {
  757.         if (pThread->m_pMainWnd == this)
  758.         {
  759.             if (!afxContextIsDLL)
  760.             {
  761.                 // shut down current thread if possible
  762.                 if (pThread != AfxGetApp() || AfxOleCanExitApp())
  763.                     AfxPostQuitMessage(0);
  764.             }
  765.             pThread->m_pMainWnd = NULL;
  766.         }
  767.         if (pThread->m_pActiveWnd == this)
  768.             pThread->m_pActiveWnd = NULL;
  769.     }
  770.  
  771. #ifndef _AFX_NO_OLE_SUPPORT
  772.     // cleanup OLE drop target interface
  773.     if (m_pDropTarget != NULL)
  774.     {
  775.         m_pDropTarget->Revoke();
  776.         m_pDropTarget = NULL;
  777.     }
  778. #endif
  779.  
  780. #ifndef _AFX_NO_OCC_SUPPORT
  781.     // cleanup control container
  782.     delete m_pCtrlCont;
  783.     m_pCtrlCont = NULL;
  784. #endif
  785.  
  786.     // cleanup tooltip support
  787.     if (m_nFlags & WF_TOOLTIPS)
  788.     {
  789.         CToolTipCtrl* pToolTip = AfxGetThreadState()->m_pToolTip;
  790.         if (pToolTip->GetSafeHwnd() != NULL)
  791.         {
  792.             TOOLINFO ti; memset(&ti, 0, sizeof(TOOLINFO));
  793.             ti.cbSize = sizeof(TOOLINFO);
  794.             ti.uFlags = TTF_IDISHWND;
  795.             ti.hwnd = m_hWnd;
  796.             ti.uId = (UINT)m_hWnd;
  797.             pToolTip->SendMessage(TTM_DELTOOL, 0, (LPARAM)&ti);
  798.         }
  799.     }
  800.  
  801.     // call default, unsubclass, and detach from the map
  802.     LONG pfnWndProc = GetWindowLong(m_hWnd, GWL_WNDPROC);
  803.     Default();
  804.     if (GetWindowLong(m_hWnd, GWL_WNDPROC) == pfnWndProc)
  805.     {
  806.         WNDPROC pfnSuper = *GetSuperWndProcAddr();
  807.         if (pfnSuper != NULL)
  808.             SetWindowLong(m_hWnd, GWL_WNDPROC, (LONG)pfnSuper);
  809.     }
  810.     Detach();
  811.     ASSERT(m_hWnd == NULL);
  812.  
  813.     // call special post-cleanup routine
  814.     PostNcDestroy();
  815. }
  816.  
  817. void CWnd::PostNcDestroy()
  818. {
  819.     // default to nothing
  820. }
  821.  
  822. void CWnd::OnFinalRelease()
  823. {
  824.     if (m_hWnd != NULL)
  825.         DestroyWindow();    // will call PostNcDestroy
  826.     else
  827.         PostNcDestroy();
  828. }
  829.  
  830. #ifdef _DEBUG
  831. void CWnd::AssertValid() const
  832. {
  833.     if (m_hWnd == NULL)
  834.         return;     // null (unattached) windows are valid
  835.  
  836.     // check for special wnd??? values
  837.     ASSERT(HWND_TOP == NULL);       // same as desktop
  838.     if (m_hWnd == HWND_BOTTOM)
  839.         ASSERT(this == &CWnd::wndBottom);
  840.     else if (m_hWnd == HWND_TOPMOST)
  841.         ASSERT(this == &CWnd::wndTopMost);
  842.     else if (m_hWnd == HWND_NOTOPMOST)
  843.         ASSERT(this == &CWnd::wndNoTopMost);
  844.     else
  845.     {
  846.         // should be a normal window
  847.         ASSERT(::IsWindow(m_hWnd));
  848.  
  849.         // should also be in the permanent or temporary handle map
  850.         CHandleMap* pMap = afxMapHWND();
  851.         ASSERT(pMap != NULL);
  852.  
  853.         CObject* p;
  854.         ASSERT((p = pMap->LookupPermanent(m_hWnd)) != NULL ||
  855.             (p = pMap->LookupTemporary(m_hWnd)) != NULL);
  856.         ASSERT((CWnd*)p == this);   // must be us
  857.  
  858.         // Note: if either of the above asserts fire and you are
  859.         // writing a multithreaded application, it is likely that
  860.         // you have passed a C++ object from one thread to another
  861.         // and have used that object in a way that was not intended.
  862.         // (only simple inline wrapper functions should be used)
  863.         //
  864.         // In general, CWnd objects should be passed by HWND from
  865.         // one thread to another.  The receiving thread can wrap
  866.         // the HWND with a CWnd object by using CWnd::FromHandle.
  867.         //
  868.         // It is dangerous to pass C++ objects from one thread to
  869.         // another, unless the objects are designed to be used in
  870.         // such a manner.
  871.     }
  872. }
  873.  
  874. void CWnd::Dump(CDumpContext& dc) const
  875. {
  876.     CObject::Dump(dc);
  877.  
  878.     dc << "\nm_hWnd = " << (UINT)m_hWnd;
  879.  
  880.     if (m_hWnd == NULL || m_hWnd == HWND_BOTTOM ||
  881.         m_hWnd == HWND_TOPMOST || m_hWnd == HWND_NOTOPMOST)
  882.     {
  883.         // not a normal window - nothing more to dump
  884.         return;
  885.     }
  886.  
  887.     if (!::IsWindow(m_hWnd))
  888.     {
  889.         // not a valid window
  890.         dc << " (illegal HWND)";
  891.         return; // don't do anything more
  892.     }
  893.  
  894.     CWnd* pWnd = CWnd::FromHandlePermanent(m_hWnd);
  895.     if (pWnd != this)
  896.         dc << " (Detached or temporary window)";
  897.     else
  898.         dc << " (permanent window)";
  899.  
  900.     // dump out window specific statistics
  901.     TCHAR szBuf [64];
  902.     if (!::SendMessage(m_hWnd, WM_QUERYAFXWNDPROC, 0, 0) && pWnd == this)
  903.         GetWindowText(szBuf, _countof(szBuf));
  904.     else
  905.         ::DefWindowProc(m_hWnd, WM_GETTEXT, _countof(szBuf), (LPARAM)&szBuf[0]);
  906.     dc << "\ncaption = \"" << szBuf << "\"";
  907.  
  908.     ::GetClassName(m_hWnd, szBuf, _countof(szBuf));
  909.     dc << "\nclass name = \"" << szBuf << "\"";
  910.  
  911.     CRect rect;
  912.     GetWindowRect(&rect);
  913.     dc << "\nrect = " << rect;
  914.     dc << "\nparent CWnd* = " << (void*)GetParent();
  915.  
  916.     dc << "\nstyle = " << (void*)::GetWindowLong(m_hWnd, GWL_STYLE);
  917.     if (::GetWindowLong(m_hWnd, GWL_STYLE) & WS_CHILD)
  918.         dc << "\nid = " << _AfxGetDlgCtrlID(m_hWnd);
  919.  
  920.     dc << "\n";
  921. }
  922. #endif
  923.  
  924. BOOL CWnd::DestroyWindow()
  925. {
  926.     if (m_hWnd == NULL)
  927.         return FALSE;
  928.  
  929.     CHandleMap* pMap = afxMapHWND();
  930.     ASSERT(pMap != NULL);
  931.     CWnd* pWnd = (CWnd*)pMap->LookupPermanent(m_hWnd);
  932. #ifdef _DEBUG
  933.     HWND hWndOrig = m_hWnd;
  934. #endif
  935.  
  936. #ifdef _AFX_NO_OCC_SUPPORT
  937.     BOOL bResult = ::DestroyWindow(m_hWnd);
  938. #else //_AFX_NO_OCC_SUPPORT
  939.     BOOL bResult;
  940.     if (m_pCtrlSite == NULL)
  941.         bResult = ::DestroyWindow(m_hWnd);
  942.     else
  943.         bResult = m_pCtrlSite->DestroyControl();
  944. #endif //_AFX_NO_OCC_SUPPORT
  945.  
  946.     // Note that 'this' may have been deleted at this point,
  947.     //  (but only if pWnd != NULL)
  948.     if (pWnd != NULL)
  949.     {
  950.         // Should have been detached by OnNcDestroy
  951.         ASSERT(pMap->LookupPermanent(hWndOrig) == NULL);
  952.     }
  953.     else
  954.     {
  955.         ASSERT(m_hWnd == hWndOrig);
  956.         // Detach after DestroyWindow called just in case
  957.         Detach();
  958.     }
  959.     return bResult;
  960. }
  961.  
  962. /////////////////////////////////////////////////////////////////////////////
  963. // Default CWnd implementation
  964.  
  965. LRESULT CWnd::DefWindowProc(UINT nMsg, WPARAM wParam, LPARAM lParam)
  966. {
  967.     if (m_pfnSuper != NULL)
  968.         return ::CallWindowProc(m_pfnSuper, m_hWnd, nMsg, wParam, lParam);
  969.  
  970.     WNDPROC pfnWndProc;
  971.     if ((pfnWndProc = *GetSuperWndProcAddr()) == NULL)
  972.         return ::DefWindowProc(m_hWnd, nMsg, wParam, lParam);
  973.     else
  974.         return ::CallWindowProc(pfnWndProc, m_hWnd, nMsg, wParam, lParam);
  975. }
  976.  
  977. WNDPROC* CWnd::GetSuperWndProcAddr()
  978. {
  979.     // Note: it is no longer necessary to override GetSuperWndProcAddr
  980.     //  for each control class with a different WNDCLASS.
  981.     //  This implementation now uses instance data, such that the previous
  982.     //  WNDPROC can be anything.
  983.  
  984.     return &m_pfnSuper;
  985. }
  986.  
  987. BOOL CWnd::PreTranslateMessage(MSG* pMsg)
  988. {
  989.     // handle tooltip messages (some messages cancel, some may cause it to popup)
  990.     AFX_MODULE_STATE* pModuleState = _AFX_CMDTARGET_GETSTATE();
  991.     if (pModuleState->m_pfnFilterToolTipMessage != NULL)
  992.         (*pModuleState->m_pfnFilterToolTipMessage)(pMsg, this);
  993.  
  994.     // no default processing
  995.     return FALSE;
  996. }
  997.  
  998. void PASCAL CWnd::CancelToolTips(BOOL bKeys)
  999. {
  1000.     // check for active tooltip
  1001.     _AFX_THREAD_STATE* pThreadState = AfxGetThreadState();
  1002.     CToolTipCtrl* pToolTip = pThreadState->m_pToolTip;
  1003.     if (pToolTip->GetSafeHwnd() != NULL)
  1004.         pToolTip->SendMessage(TTM_ACTIVATE, FALSE);
  1005.  
  1006.     // check for active control bar fly-by status
  1007.     CControlBar* pLastStatus = pThreadState->m_pLastStatus;
  1008.     if (bKeys && pLastStatus != NULL && GetKeyState(VK_LBUTTON) >= 0)
  1009.         pLastStatus->SetStatusText(-1);
  1010. }
  1011.  
  1012. int CWnd::OnToolHitTest(CPoint point, TOOLINFO* pTI) const
  1013. {
  1014.     // find child window which hits the point
  1015.     // (don't use WindowFromPoint, because it ignores disabled windows)
  1016.     HWND hWndChild = _AfxChildWindowFromPoint(m_hWnd, point);
  1017.     if (hWndChild != NULL)
  1018.     {
  1019.         // return positive hit if control ID isn't -1
  1020.         int nHit = _AfxGetDlgCtrlID(hWndChild);
  1021.  
  1022.         // hits against child windows always center the tip
  1023.         if (pTI != NULL && pTI->cbSize >= sizeof(TOOLINFO))
  1024.         {
  1025.             // setup the TOOLINFO structure
  1026.             pTI->hwnd = m_hWnd;
  1027.             pTI->uId = (UINT)hWndChild;
  1028.             pTI->uFlags |= TTF_IDISHWND;
  1029.             pTI->lpszText = LPSTR_TEXTCALLBACK;
  1030.  
  1031.             // set TTF_NOTBUTTON and TTF_CENTERTIP if it isn't a button
  1032.             if (!(::SendMessage(hWndChild, WM_GETDLGCODE, 0, 0) & DLGC_BUTTON))
  1033.                 pTI->uFlags |= TTF_NOTBUTTON|TTF_CENTERTIP;
  1034.         }
  1035.         return nHit;
  1036.     }
  1037.     return -1;  // not found
  1038. }
  1039.  
  1040. void CWnd::GetWindowText(CString& rString) const
  1041. {
  1042.     ASSERT(::IsWindow(m_hWnd));
  1043.  
  1044. #ifndef _AFX_NO_OCC_SUPPORT
  1045.     if (m_pCtrlSite == NULL)
  1046.     {
  1047. #endif
  1048.         int nLen = ::GetWindowTextLength(m_hWnd);
  1049.         ::GetWindowText(m_hWnd, rString.GetBufferSetLength(nLen), nLen+1);
  1050.         rString.ReleaseBuffer();
  1051.  
  1052. #ifndef _AFX_NO_OCC_SUPPORT
  1053.     }
  1054.     else
  1055.     {
  1056.         m_pCtrlSite->GetWindowText(rString);
  1057.     }
  1058. #endif
  1059. }
  1060.  
  1061. int CWnd::GetDlgItemText(int nID, CString& rString) const
  1062. {
  1063.     ASSERT(::IsWindow(m_hWnd));
  1064.     rString = &afxChNil;    // empty without deallocating
  1065.  
  1066. #ifndef _AFX_NO_OCC_SUPPORT
  1067.     if (m_pCtrlCont == NULL)
  1068.     {
  1069. #endif
  1070.         HWND hWnd = ::GetDlgItem(m_hWnd, nID);
  1071.         if (hWnd != NULL)
  1072.         {
  1073.             int nLen = ::GetWindowTextLength(hWnd);
  1074.             ::GetWindowText(hWnd, rString.GetBufferSetLength(nLen), nLen+1);
  1075.             rString.ReleaseBuffer();
  1076.         }
  1077.  
  1078. #ifndef _AFX_NO_OCC_SUPPORT
  1079.     }
  1080.     else
  1081.     {
  1082.         CWnd* pWnd = GetDlgItem(nID);
  1083.         if (pWnd != NULL)
  1084.             pWnd->GetWindowText(rString);
  1085.     }
  1086. #endif
  1087.  
  1088.     return rString.GetLength();
  1089. }
  1090.  
  1091. BOOL CWnd::GetWindowPlacement(WINDOWPLACEMENT* lpwndpl) const
  1092. {
  1093.     ASSERT(::IsWindow(m_hWnd));
  1094.     lpwndpl->length = sizeof(WINDOWPLACEMENT);
  1095.     return ::GetWindowPlacement(m_hWnd, lpwndpl);
  1096. }
  1097.  
  1098. BOOL CWnd::SetWindowPlacement(const WINDOWPLACEMENT* lpwndpl)
  1099. {
  1100.     ASSERT(::IsWindow(m_hWnd));
  1101.     ((WINDOWPLACEMENT*)lpwndpl)->length = sizeof(WINDOWPLACEMENT);
  1102.     return ::SetWindowPlacement(m_hWnd, lpwndpl);
  1103. }
  1104.  
  1105. /////////////////////////////////////////////////////////////////////////////
  1106. // CWnd will delegate owner draw messages to self drawing controls
  1107.  
  1108. // Drawing: for all 4 control types
  1109. void CWnd::OnDrawItem(int /*nIDCtl*/, LPDRAWITEMSTRUCT lpDrawItemStruct)
  1110. {
  1111.     if (lpDrawItemStruct->CtlType == ODT_MENU)
  1112.     {
  1113.         CMenu* pMenu = CMenu::FromHandlePermanent(
  1114.             (HMENU)lpDrawItemStruct->hwndItem);
  1115.         if (pMenu != NULL)
  1116.         {
  1117.             pMenu->DrawItem(lpDrawItemStruct);
  1118.             return; // eat it
  1119.         }
  1120.     }
  1121.     else
  1122.     {
  1123.         // reflect notification to child window control
  1124.         if (ReflectLastMsg(lpDrawItemStruct->hwndItem))
  1125.             return;     // eat it
  1126.     }
  1127.     // not handled - do default
  1128.     Default();
  1129. }
  1130.  
  1131. // Drawing: for all 4 control types
  1132. int CWnd::OnCompareItem(int /*nIDCtl*/, LPCOMPAREITEMSTRUCT lpCompareItemStruct)
  1133. {
  1134.     // reflect notification to child window control
  1135.     LRESULT lResult;
  1136.     if (ReflectLastMsg(lpCompareItemStruct->hwndItem, &lResult))
  1137.         return (int)lResult;        // eat it
  1138.  
  1139.     // not handled - do default
  1140.     return (int)Default();
  1141. }
  1142.  
  1143. void CWnd::OnDeleteItem(int /*nIDCtl*/, LPDELETEITEMSTRUCT lpDeleteItemStruct)
  1144. {
  1145.     // reflect notification to child window control
  1146.     if (ReflectLastMsg(lpDeleteItemStruct->hwndItem))
  1147.         return;     // eat it
  1148.     // not handled - do default
  1149.     Default();
  1150. }
  1151.  
  1152. int CWnd::OnCharToItem(UINT, CListBox* pWnd, UINT)
  1153. {
  1154.     if (pWnd != NULL)
  1155.     {
  1156.         LRESULT lResult;
  1157.         if (pWnd->SendChildNotifyLastMsg(&lResult))
  1158.             return (int)lResult;     // eat it
  1159.     }
  1160.     // not handled - do default
  1161.     return (int)Default();
  1162. }
  1163.  
  1164. int CWnd::OnVKeyToItem(UINT, CListBox* pWnd, UINT)
  1165. {
  1166.     if (pWnd != NULL)
  1167.     {
  1168.         LRESULT lResult;
  1169.         if (pWnd->SendChildNotifyLastMsg(&lResult))
  1170.             return (int)lResult;     // eat it
  1171.     }
  1172.     // not handled - do default
  1173.     return (int)Default();
  1174. }
  1175.  
  1176. /////////////////////////////////////////////////////////////////////////////
  1177. // Self drawing menus are a little trickier
  1178.  
  1179. BOOL CMenu::TrackPopupMenu(UINT nFlags, int x, int y,
  1180.         CWnd* pWnd, LPCRECT lpRect)
  1181. {
  1182.     ASSERT(m_hMenu != NULL);
  1183.  
  1184.     _AFX_THREAD_STATE* pThreadState = AfxGetThreadState();
  1185.     HWND hWndOld = pThreadState->m_hTrackingWindow;
  1186.     HMENU hMenuOld = pThreadState->m_hTrackingMenu;
  1187.     pThreadState->m_hTrackingWindow = pWnd->GetSafeHwnd();
  1188.     pThreadState->m_hTrackingMenu = m_hMenu;
  1189.     BOOL bOK = ::TrackPopupMenu(m_hMenu, nFlags, x, y, 0,
  1190.             pThreadState->m_hTrackingWindow, lpRect);
  1191.     pThreadState->m_hTrackingWindow = hWndOld;
  1192.     pThreadState->m_hTrackingMenu = hMenuOld;
  1193.  
  1194.     return bOK;
  1195. }
  1196.  
  1197. static CMenu* FindPopupMenuFromID(CMenu* pMenu, UINT nID)
  1198. {
  1199.     ASSERT_VALID(pMenu);
  1200.     // walk through all items, looking for ID match
  1201.     UINT nItems = pMenu->GetMenuItemCount();
  1202.     for (int iItem = 0; iItem < (int)nItems; iItem++)
  1203.     {
  1204.         CMenu* pPopup = pMenu->GetSubMenu(iItem);
  1205.         if (pPopup != NULL)
  1206.         {
  1207.             // recurse to child popup
  1208.             pPopup = FindPopupMenuFromID(pPopup, nID);
  1209.             // check popups on this popup
  1210.             if (pPopup != NULL)
  1211.                 return pPopup;
  1212.         }
  1213.         else if (pMenu->GetMenuItemID(iItem) == nID)
  1214.         {
  1215.             // it is a normal item inside our popup
  1216.             pMenu = CMenu::FromHandlePermanent(pMenu->m_hMenu);
  1217.             return pMenu;
  1218.         }
  1219.     }
  1220.     // not found
  1221.     return NULL;
  1222. }
  1223.  
  1224. // Measure item implementation relies on unique control/menu IDs
  1225. void CWnd::OnMeasureItem(int /*nIDCtl*/, LPMEASUREITEMSTRUCT lpMeasureItemStruct)
  1226. {
  1227.     if (lpMeasureItemStruct->CtlType == ODT_MENU)
  1228.     {
  1229.         ASSERT(lpMeasureItemStruct->CtlID == 0);
  1230.         CMenu* pMenu;
  1231.  
  1232.         _AFX_THREAD_STATE* pThreadState = _afxThreadState.GetData();
  1233.         if (pThreadState->m_hTrackingWindow == m_hWnd)
  1234.         {
  1235.             // start from popup
  1236.             pMenu = CMenu::FromHandle(pThreadState->m_hTrackingMenu);
  1237.         }
  1238.         else
  1239.         {
  1240.             // start from menubar
  1241.             pMenu = GetMenu();
  1242.         }
  1243.  
  1244.         pMenu = FindPopupMenuFromID(pMenu, lpMeasureItemStruct->itemID);
  1245.         if (pMenu != NULL)
  1246.             pMenu->MeasureItem(lpMeasureItemStruct);
  1247.         else
  1248.             TRACE1("Warning: unknown WM_MEASUREITEM for menu item 0x%04X.\n",
  1249.                 lpMeasureItemStruct->itemID);
  1250.     }
  1251.     else
  1252.     {
  1253.         CWnd* pChild = GetDescendantWindow(lpMeasureItemStruct->CtlID, TRUE);
  1254.         if (pChild != NULL && pChild->SendChildNotifyLastMsg())
  1255.             return;     // eaten by child
  1256.     }
  1257.     // not handled - do default
  1258.     Default();
  1259. }
  1260.  
  1261. /////////////////////////////////////////////////////////////////////////////
  1262. // Additional helpers for WNDCLASS init
  1263.  
  1264. // like RegisterClass, except will automatically call UnregisterClass
  1265. BOOL AFXAPI AfxRegisterClass(WNDCLASS* lpWndClass)
  1266. {
  1267.     WNDCLASS wndcls;
  1268.     if (GetClassInfo(lpWndClass->hInstance, lpWndClass->lpszClassName,
  1269.         &wndcls))
  1270.     {
  1271.         // class already registered
  1272.         return TRUE;
  1273.     }
  1274.  
  1275.     if (!::RegisterClass(lpWndClass))
  1276.     {
  1277.         TRACE1("Can't register window class named %s\n",
  1278.             lpWndClass->lpszClassName);
  1279.         return FALSE;
  1280.     }
  1281.  
  1282.     if (afxContextIsDLL)
  1283.     {
  1284.         AfxLockGlobals(CRIT_REGCLASSLIST);
  1285.         TRY
  1286.         {
  1287.             // class registered successfully, add to registered list
  1288.             AFX_MODULE_STATE* pModuleState = AfxGetModuleState();
  1289.             LPTSTR lpszUnregisterList = pModuleState->m_szUnregisterList;
  1290.             // the buffer is of fixed size -- ensure that it does not overflow
  1291.             ASSERT(lstrlen(lpszUnregisterList) + 1 +
  1292.                 lstrlen(lpWndClass->lpszClassName) + 1 <
  1293.                 _countof(pModuleState->m_szUnregisterList));
  1294.             // append classname + newline to m_szUnregisterList
  1295.             lstrcat(lpszUnregisterList, lpWndClass->lpszClassName);
  1296.             TCHAR szTemp[2];
  1297.             szTemp[0] = '\n';
  1298.             szTemp[1] = '\0';
  1299.             lstrcat(lpszUnregisterList, szTemp);
  1300.         }
  1301.         CATCH_ALL(e)
  1302.         {
  1303.             AfxUnlockGlobals(CRIT_REGCLASSLIST);
  1304.             THROW_LAST();
  1305.             // Note: DELETE_EXCEPTION not required.
  1306.         }
  1307.         END_CATCH_ALL
  1308.         AfxUnlockGlobals(CRIT_REGCLASSLIST);
  1309.     }
  1310.  
  1311.     return TRUE;
  1312. }
  1313.  
  1314. LPCTSTR AFXAPI AfxRegisterWndClass(UINT nClassStyle,
  1315.     HCURSOR hCursor, HBRUSH hbrBackground, HICON hIcon)
  1316. {
  1317.     // Returns a temporary string name for the class
  1318.     //  Save in a CString if you want to use it for a long time
  1319.     LPTSTR lpszName = AfxGetThreadState()->m_szTempClassName;
  1320.  
  1321.     // generate a synthetic name for this class
  1322.     HINSTANCE hInst = AfxGetInstanceHandle();
  1323.     if (hCursor == NULL && hbrBackground == NULL && hIcon == NULL)
  1324.         wsprintf(lpszName, _T("Afx:%x:%x"), (UINT)hInst, nClassStyle);
  1325.     else
  1326.         wsprintf(lpszName, _T("Afx:%x:%x:%x:%x:%x"), (UINT)hInst, nClassStyle,
  1327.             (UINT)hCursor, (UINT)hbrBackground, (UINT)hIcon);
  1328.  
  1329.     // see if the class already exists
  1330.     WNDCLASS wndcls;
  1331.     if (::GetClassInfo(hInst, lpszName, &wndcls))
  1332.     {
  1333.         // already registered, assert everything is good
  1334.         ASSERT(wndcls.style == nClassStyle);
  1335.  
  1336.         // NOTE: We have to trust that the hIcon, hbrBackground, and the
  1337.         //  hCursor are semantically the same, because sometimes Windows does
  1338.         //  some internal translation or copying of those handles before
  1339.         //  storing them in the internal WNDCLASS retrieved by GetClassInfo.
  1340.         return lpszName;
  1341.     }
  1342.  
  1343.     // otherwise we need to register a new class
  1344.     wndcls.style = nClassStyle;
  1345.     wndcls.lpfnWndProc = DefWindowProc;
  1346.     wndcls.cbClsExtra = wndcls.cbWndExtra = 0;
  1347.     wndcls.hInstance = hInst;
  1348.     wndcls.hIcon = hIcon;
  1349.     wndcls.hCursor = hCursor;
  1350.     wndcls.hbrBackground = hbrBackground;
  1351.     wndcls.lpszMenuName = NULL;
  1352.     wndcls.lpszClassName = lpszName;
  1353.     if (!AfxRegisterClass(&wndcls))
  1354.         AfxThrowResourceException();
  1355.  
  1356.     // return thread-local pointer
  1357.     return lpszName;
  1358. }
  1359.  
  1360. struct AFX_CTLCOLOR
  1361. {
  1362.     HWND hWnd;
  1363.     HDC hDC;
  1364.     UINT nCtlType;
  1365. };
  1366.  
  1367. LRESULT CWnd::OnNTCtlColor(WPARAM wParam, LPARAM lParam)
  1368. {
  1369.     // fill in special struct for compatiblity with 16-bit WM_CTLCOLOR
  1370.     AFX_CTLCOLOR ctl;
  1371.     ctl.hDC = (HDC)wParam;
  1372.     ctl.hWnd = (HWND)lParam;
  1373.     ctl.nCtlType = GetCurrentMessage()->message - WM_CTLCOLORMSGBOX;
  1374.     ASSERT(ctl.nCtlType >= CTLCOLOR_MSGBOX);
  1375.     ASSERT(ctl.nCtlType <= CTLCOLOR_STATIC);
  1376.  
  1377.     // Note: We call the virtual WindowProc for this window directly,
  1378.     //  instead of calling AfxCallWindowProc, so that Default()
  1379.     //  will still work (it will call the Default window proc with
  1380.     //  the original Win32 WM_CTLCOLOR message).
  1381.     return WindowProc(WM_CTLCOLOR, 0, (LPARAM)&ctl);
  1382. }
  1383.  
  1384. /////////////////////////////////////////////////////////////////////////////
  1385. // CWnd extensions for help support
  1386.  
  1387. void CWnd::WinHelp(DWORD dwData, UINT nCmd)
  1388. {
  1389.     CWinApp* pApp = AfxGetApp();
  1390.     ASSERT_VALID(pApp);
  1391.     ASSERT(pApp->m_pszHelpFilePath != NULL);
  1392.  
  1393.     CWaitCursor wait;
  1394.     if (IsFrameWnd())
  1395.     {
  1396.         // CFrameWnd windows should be allowed to exit help mode first
  1397.         CFrameWnd* pFrameWnd = (CFrameWnd*)this;
  1398.         pFrameWnd->ExitHelpMode();
  1399.     }
  1400.  
  1401.     // cancel any tracking modes
  1402.     SendMessage(WM_CANCELMODE);
  1403.     SendMessageToDescendants(WM_CANCELMODE, 0, 0, TRUE, TRUE);
  1404.  
  1405.     // need to use top level parent (for the case where m_hWnd is in DLL)
  1406.     CWnd* pWnd = GetTopLevelParent();
  1407.     pWnd->SendMessage(WM_CANCELMODE);
  1408.     pWnd->SendMessageToDescendants(WM_CANCELMODE, 0, 0, TRUE, TRUE);
  1409.  
  1410.     // attempt to cancel capture
  1411.     HWND hWndCapture = ::GetCapture();
  1412.     if (hWndCapture != NULL)
  1413.         ::SendMessage(hWndCapture, WM_CANCELMODE, 0, 0);
  1414.  
  1415.     TRACE3("WinHelp: pszHelpFile = '%s', dwData: $%lx, fuCommand: %d.\n",
  1416.         pApp->m_pszHelpFilePath, dwData, nCmd);
  1417.  
  1418.     // finally, run the Windows Help engine
  1419.     if (!::WinHelp(pWnd->m_hWnd, pApp->m_pszHelpFilePath, nCmd, dwData))
  1420.         AfxMessageBox(AFX_IDP_FAILED_TO_LAUNCH_HELP);
  1421. }
  1422.  
  1423. /////////////////////////////////////////////////////////////////////////////
  1424. // Message table implementation
  1425.  
  1426. BEGIN_MESSAGE_MAP(CWnd, CCmdTarget)
  1427.     ON_MESSAGE(WM_CTLCOLORSTATIC, OnNTCtlColor)
  1428.     ON_MESSAGE(WM_CTLCOLOREDIT, OnNTCtlColor)
  1429.     ON_MESSAGE(WM_CTLCOLORBTN, OnNTCtlColor)
  1430.     ON_MESSAGE(WM_CTLCOLORLISTBOX, OnNTCtlColor)
  1431.     ON_MESSAGE(WM_CTLCOLORDLG, OnNTCtlColor)
  1432.     ON_MESSAGE(WM_CTLCOLORMSGBOX, OnNTCtlColor)
  1433.     ON_MESSAGE(WM_CTLCOLORSCROLLBAR, OnNTCtlColor)
  1434.     //{{AFX_MSG_MAP(CWnd)
  1435.     ON_WM_DRAWITEM()
  1436.     ON_WM_MEASUREITEM()
  1437.     ON_WM_CTLCOLOR()
  1438.     ON_WM_COMPAREITEM()
  1439.     ON_WM_ENTERIDLE()
  1440.     ON_WM_HSCROLL()
  1441.     ON_WM_VSCROLL()
  1442.     ON_WM_DELETEITEM()
  1443.     ON_WM_CHARTOITEM()
  1444.     ON_WM_VKEYTOITEM()
  1445.     ON_WM_NCDESTROY()
  1446.     ON_WM_PARENTNOTIFY()
  1447.     ON_WM_SYSCOLORCHANGE()
  1448.     ON_WM_DEVMODECHANGE()
  1449.     ON_WM_HELPINFO()
  1450.     ON_WM_SETTINGCHANGE()
  1451. #ifndef _AFX_NO_OCC_SUPPORT
  1452.     ON_WM_DESTROY()
  1453. #endif
  1454.     //}}AFX_MSG_MAP
  1455.     ON_MESSAGE(WM_ACTIVATETOPLEVEL, OnActivateTopLevel)
  1456.     ON_MESSAGE(WM_DISPLAYCHANGE, OnDisplayChange)
  1457. #ifdef _MAC
  1458.     ON_MESSAGE(WM_MACINTOSH, OnMacintosh)
  1459. #endif
  1460.     ON_REGISTERED_MESSAGE(CWnd::m_nMsgDragList, OnDragList)
  1461. END_MESSAGE_MAP()
  1462.  
  1463. /////////////////////////////////////////////////////////////////////////////
  1464. // Routines for fast search of message maps
  1465.  
  1466. const AFX_MSGMAP_ENTRY* AFXAPI
  1467. AfxFindMessageEntry(const AFX_MSGMAP_ENTRY* lpEntry,
  1468.     UINT nMsg, UINT nCode, UINT nID)
  1469. {
  1470. #if defined(_M_IX86) && !defined(_AFX_PORTABLE)
  1471. // 32-bit Intel 386/486 version.
  1472.  
  1473.     ASSERT(offsetof(AFX_MSGMAP_ENTRY, nMessage) == 0);
  1474.     ASSERT(offsetof(AFX_MSGMAP_ENTRY, nCode) == 4);
  1475.     ASSERT(offsetof(AFX_MSGMAP_ENTRY, nID) == 8);
  1476.     ASSERT(offsetof(AFX_MSGMAP_ENTRY, nLastID) == 12);
  1477.     ASSERT(offsetof(AFX_MSGMAP_ENTRY, nSig) == 16);
  1478.  
  1479.     _asm
  1480.     {
  1481.             MOV     EBX,lpEntry
  1482.             MOV     EAX,nMsg
  1483.             MOV     EDX,nCode
  1484.             MOV     ECX,nID
  1485.     __loop:
  1486.             CMP     DWORD PTR [EBX+16],0        ; nSig (0 => end)
  1487.             JZ      __failed
  1488.             CMP     EAX,DWORD PTR [EBX]         ; nMessage
  1489.             JE      __found_message
  1490.     __next:
  1491.             ADD     EBX,SIZE AFX_MSGMAP_ENTRY
  1492.             JMP     short __loop
  1493.     __found_message:
  1494.             CMP     EDX,DWORD PTR [EBX+4]       ; nCode
  1495.             JNE     __next
  1496.     // message and code good so far
  1497.     // check the ID
  1498.             CMP     ECX,DWORD PTR [EBX+8]       ; nID
  1499.             JB      __next
  1500.             CMP     ECX,DWORD PTR [EBX+12]      ; nLastID
  1501.             JA      __next
  1502.     // found a match
  1503.             MOV     lpEntry,EBX                 ; return EBX
  1504.             JMP     short __end
  1505.     __failed:
  1506.             XOR     EAX,EAX                     ; return NULL
  1507.             MOV     lpEntry,EAX
  1508.     __end:
  1509.     }
  1510.     return lpEntry;
  1511. #else  // _AFX_PORTABLE
  1512.     // C version of search routine
  1513.     while (lpEntry->nSig != AfxSig_end)
  1514.     {
  1515.         if (lpEntry->nMessage == nMsg && lpEntry->nCode == nCode &&
  1516.             nID >= lpEntry->nID && nID <= lpEntry->nLastID)
  1517.         {
  1518.             return lpEntry;
  1519.         }
  1520.         lpEntry++;
  1521.     }
  1522.     return NULL;    // not found
  1523. #endif  // _AFX_PORTABLE
  1524. }
  1525.  
  1526. /////////////////////////////////////////////////////////////////////////////
  1527. // Cache of most recently sent messages
  1528.  
  1529. #ifndef iHashMax
  1530. // iHashMax must be a power of two
  1531.     #define iHashMax 512
  1532. #endif
  1533.  
  1534. struct AFX_MSG_CACHE
  1535. {
  1536.     UINT nMsg;
  1537.     const AFX_MSGMAP_ENTRY* lpEntry;
  1538.     const AFX_MSGMAP* pMessageMap;
  1539. };
  1540.  
  1541. AFX_MSG_CACHE _afxMsgCache[iHashMax];
  1542.  
  1543. void AFXAPI AfxResetMsgCache()
  1544. {
  1545.     memset(_afxMsgCache, 0, sizeof(_afxMsgCache));
  1546. }
  1547.  
  1548. /////////////////////////////////////////////////////////////////////////////
  1549. // main WindowProc implementation
  1550.  
  1551. LRESULT CWnd::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
  1552. {
  1553.     // OnWndMsg does most of the work, except for DefWindowProc call
  1554.     LRESULT lResult = 0;
  1555.     if (!OnWndMsg(message, wParam, lParam, &lResult))
  1556.         lResult = DefWindowProc(message, wParam, lParam);
  1557.     return lResult;
  1558. }
  1559.  
  1560. BOOL CWnd::OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult)
  1561. {
  1562.     LRESULT lResult = 0;
  1563.  
  1564.     // special case for commands
  1565.     if (message == WM_COMMAND)
  1566.     {
  1567.         if (OnCommand(wParam, lParam))
  1568.         {
  1569.             lResult = 1;
  1570.             goto LReturnTrue;
  1571.         }
  1572.         return FALSE;
  1573.     }
  1574.  
  1575.     // special case for notifies
  1576.     if (message == WM_NOTIFY)
  1577.     {
  1578.         NMHDR* pNMHDR = (NMHDR*)lParam;
  1579.         if (pNMHDR->hwndFrom != NULL && OnNotify(wParam, lParam, &lResult))
  1580.             goto LReturnTrue;
  1581.         return FALSE;
  1582.     }
  1583.  
  1584.     // special case for activation
  1585.     if (message == WM_ACTIVATE)
  1586.         _AfxHandleActivate(this, wParam, CWnd::FromHandle((HWND)lParam));
  1587.  
  1588.     // special case for set cursor HTERROR
  1589.     if (message == WM_SETCURSOR &&
  1590.         _AfxHandleSetCursor(this, (short)LOWORD(lParam), HIWORD(lParam)))
  1591.     {
  1592.         lResult = 1;
  1593.         goto LReturnTrue;
  1594.     }
  1595.  
  1596.     const AFX_MSGMAP* pMessageMap; pMessageMap = GetMessageMap();
  1597.     UINT iHash; iHash = (LOWORD((DWORD)pMessageMap) ^ message) & (iHashMax-1);
  1598.     AfxLockGlobals(CRIT_WINMSGCACHE);
  1599.     AFX_MSG_CACHE* pMsgCache; pMsgCache = &_afxMsgCache[iHash];
  1600.     const AFX_MSGMAP_ENTRY* lpEntry;
  1601.     if (message == pMsgCache->nMsg && pMessageMap == pMsgCache->pMessageMap)
  1602.     {
  1603.         // cache hit
  1604.         lpEntry = pMsgCache->lpEntry;
  1605.         AfxUnlockGlobals(CRIT_WINMSGCACHE);
  1606.         if (lpEntry == NULL)
  1607.             return FALSE;
  1608.  
  1609.         // cache hit, and it needs to be handled
  1610.         if (message < 0xC000)
  1611.             goto LDispatch;
  1612.         else
  1613.             goto LDispatchRegistered;
  1614.     }
  1615.     else
  1616.     {
  1617.         // not in cache, look for it
  1618.         pMsgCache->nMsg = message;
  1619.         pMsgCache->pMessageMap = pMessageMap;
  1620.  
  1621. #ifdef _AFXDLL
  1622.         for (/* pMessageMap already init'ed */; pMessageMap != NULL;
  1623.             pMessageMap = (*pMessageMap->pfnGetBaseMap)())
  1624. #else
  1625.         for (/* pMessageMap already init'ed */; pMessageMap != NULL;
  1626.             pMessageMap = pMessageMap->pBaseMap)
  1627. #endif
  1628.         {
  1629.             // Note: catch not so common but fatal mistake!!
  1630.             //      BEGIN_MESSAGE_MAP(CMyWnd, CMyWnd)
  1631. #ifdef _AFXDLL
  1632.             ASSERT(pMessageMap != (*pMessageMap->pfnGetBaseMap)());
  1633. #else
  1634.             ASSERT(pMessageMap != pMessageMap->pBaseMap);
  1635. #endif
  1636.  
  1637.             if (message < 0xC000)
  1638.             {
  1639.                 // constant window message
  1640.                 if ((lpEntry = AfxFindMessageEntry(pMessageMap->lpEntries,
  1641.                     message, 0, 0)) != NULL)
  1642.                 {
  1643.                     pMsgCache->lpEntry = lpEntry;
  1644.                     AfxUnlockGlobals(CRIT_WINMSGCACHE);
  1645.                     goto LDispatch;
  1646.                 }
  1647.             }
  1648.             else
  1649.             {
  1650.                 // registered windows message
  1651.                 lpEntry = pMessageMap->lpEntries;
  1652.                 while ((lpEntry = AfxFindMessageEntry(lpEntry, 0xC000, 0, 0)) != NULL)
  1653.                 {
  1654.                     UINT* pnID = (UINT*)(lpEntry->nSig);
  1655.                     ASSERT(*pnID >= 0xC000 || *pnID == 0);
  1656.                         // must be successfully registered
  1657.                     if (*pnID == message)
  1658.                     {
  1659.                         pMsgCache->lpEntry = lpEntry;
  1660.                         AfxUnlockGlobals(CRIT_WINMSGCACHE);
  1661.                         goto LDispatchRegistered;
  1662.                     }
  1663.                     lpEntry++;      // keep looking past this one
  1664.                 }
  1665.             }
  1666.         }
  1667.  
  1668.         pMsgCache->lpEntry = NULL;
  1669.         AfxUnlockGlobals(CRIT_WINMSGCACHE);
  1670.         return FALSE;
  1671.     }
  1672.     ASSERT(FALSE);      // not reached
  1673.  
  1674. LDispatch:
  1675.     ASSERT(message < 0xC000);
  1676.     union MessageMapFunctions mmf;
  1677.     mmf.pfn = lpEntry->pfn;
  1678.  
  1679.     // if we've got WM_SETTINGCHANGE / WM_WININICHANGE, we need to
  1680.     // decide if we're going to call OnWinIniChange() or OnSettingChange()
  1681.  
  1682.     int nSig;
  1683.     nSig = lpEntry->nSig;
  1684.     if (lpEntry->nID == WM_SETTINGCHANGE)
  1685.     {
  1686.         DWORD dwVersion = GetVersion();
  1687.         if (LOBYTE(LOWORD(dwVersion)) >= 4)
  1688.             nSig = AfxSig_vws;
  1689.         else
  1690.             nSig = AfxSig_vs;
  1691.     }
  1692.  
  1693.     switch (nSig)
  1694.     {
  1695.     default:
  1696.         ASSERT(FALSE);
  1697.         break;
  1698.  
  1699.     case AfxSig_bD:
  1700.         lResult = (this->*mmf.pfn_bD)(CDC::FromHandle((HDC)wParam));
  1701.         break;
  1702.  
  1703.     case AfxSig_bb:     // AfxSig_bb, AfxSig_bw, AfxSig_bh
  1704.         lResult = (this->*mmf.pfn_bb)((BOOL)wParam);
  1705.         break;
  1706.  
  1707.     case AfxSig_bWww:   // really AfxSig_bWiw
  1708.         lResult = (this->*mmf.pfn_bWww)(CWnd::FromHandle((HWND)wParam),
  1709.             (short)LOWORD(lParam), HIWORD(lParam));
  1710.         break;
  1711.  
  1712.     case AfxSig_bWCDS:
  1713.         lResult = (this->*mmf.pfn_bWCDS)(CWnd::FromHandle((HWND)lParam),
  1714.             (COPYDATASTRUCT*) lParam);
  1715.         break;
  1716.  
  1717.     case AfxSig_bHELPINFO:
  1718.         lResult = (this->*mmf.pfn_bHELPINFO)((HELPINFO*)lParam);
  1719.         break;
  1720.  
  1721.     case AfxSig_hDWw:
  1722.         {
  1723.             // special case for OnCtlColor to avoid too many temporary objects
  1724.             ASSERT(message == WM_CTLCOLOR);
  1725.             AFX_CTLCOLOR* pCtl = (AFX_CTLCOLOR*)lParam;
  1726.             CDC dcTemp; dcTemp.m_hDC = pCtl->hDC;
  1727.             CWnd wndTemp; wndTemp.m_hWnd = pCtl->hWnd;
  1728.             UINT nCtlType = pCtl->nCtlType;
  1729.             // if not coming from a permanent window, use stack temporary
  1730.             CWnd* pWnd = CWnd::FromHandlePermanent(wndTemp.m_hWnd);
  1731.             if (pWnd == NULL)
  1732.             {
  1733. #ifndef _AFX_NO_OCC_SUPPORT
  1734.                 // determine the site of the OLE control if it is one
  1735.                 COleControlSite* pSite;
  1736.                 if (m_pCtrlCont != NULL && (pSite = (COleControlSite*)
  1737.                     m_pCtrlCont->m_siteMap.GetValueAt(wndTemp.m_hWnd)) != NULL)
  1738.                 {
  1739.                     wndTemp.m_pCtrlSite = pSite;
  1740.                 }
  1741. #endif
  1742.                 pWnd = &wndTemp;
  1743.             }
  1744.             HBRUSH hbr = (this->*mmf.pfn_hDWw)(&dcTemp, pWnd, nCtlType);
  1745.             // fast detach of temporary objects
  1746.             dcTemp.m_hDC = NULL;
  1747.             wndTemp.m_hWnd = NULL;
  1748.             lResult = (LRESULT)hbr;
  1749.         }
  1750.         break;
  1751.  
  1752.     case AfxSig_hDw:
  1753.         {
  1754.             // special case for CtlColor to avoid too many temporary objects
  1755.             ASSERT(message == WM_REFLECT_BASE+WM_CTLCOLOR);
  1756.             AFX_CTLCOLOR* pCtl = (AFX_CTLCOLOR*)lParam;
  1757.             CDC dcTemp; dcTemp.m_hDC = pCtl->hDC;
  1758.             UINT nCtlType = pCtl->nCtlType;
  1759.             HBRUSH hbr = (this->*mmf.pfn_hDw)(&dcTemp, nCtlType);
  1760.             // fast detach of temporary objects
  1761.             dcTemp.m_hDC = NULL;
  1762.             lResult = (LRESULT)hbr;
  1763.         }
  1764.         break;
  1765.  
  1766.     case AfxSig_iwWw:
  1767.         lResult = (this->*mmf.pfn_iwWw)(LOWORD(wParam),
  1768.             CWnd::FromHandle((HWND)lParam), HIWORD(wParam));
  1769.         break;
  1770.  
  1771.     case AfxSig_iww:
  1772.         lResult = (this->*mmf.pfn_iww)(LOWORD(wParam), HIWORD(wParam));
  1773.         break;
  1774.  
  1775.     case AfxSig_iWww:   // really AfxSig_iWiw
  1776.         lResult = (this->*mmf.pfn_iWww)(CWnd::FromHandle((HWND)wParam),
  1777.             (short)LOWORD(lParam), HIWORD(lParam));
  1778.         break;
  1779.  
  1780.     case AfxSig_is:
  1781.         lResult = (this->*mmf.pfn_is)((LPTSTR)lParam);
  1782.         break;
  1783.  
  1784.     case AfxSig_lwl:
  1785.         lResult = (this->*mmf.pfn_lwl)(wParam, lParam);
  1786.         break;
  1787.  
  1788.     case AfxSig_lwwM:
  1789.         lResult = (this->*mmf.pfn_lwwM)((UINT)LOWORD(wParam),
  1790.             (UINT)HIWORD(wParam), (CMenu*)CMenu::FromHandle((HMENU)lParam));
  1791.         break;
  1792.  
  1793.     case AfxSig_vv:
  1794.         (this->*mmf.pfn_vv)();
  1795.         break;
  1796.  
  1797.     case AfxSig_vw: // AfxSig_vb, AfxSig_vh
  1798.         (this->*mmf.pfn_vw)(wParam);
  1799.         break;
  1800.  
  1801.     case AfxSig_vww:
  1802.         (this->*mmf.pfn_vww)((UINT)wParam, (UINT)lParam);
  1803.         break;
  1804.  
  1805.     case AfxSig_vvii:
  1806.         (this->*mmf.pfn_vvii)((short)LOWORD(lParam), (short)HIWORD(lParam));
  1807.         break;
  1808.  
  1809.     case AfxSig_vwww:
  1810.         (this->*mmf.pfn_vwww)(wParam, LOWORD(lParam), HIWORD(lParam));
  1811.         break;
  1812.  
  1813.     case AfxSig_vwii:
  1814.         (this->*mmf.pfn_vwii)(wParam, LOWORD(lParam), HIWORD(lParam));
  1815.         break;
  1816.  
  1817.     case AfxSig_vwl:
  1818.         (this->*mmf.pfn_vwl)(wParam, lParam);
  1819.         break;
  1820.  
  1821.     case AfxSig_vbWW:
  1822.         (this->*mmf.pfn_vbWW)(m_hWnd == (HWND)lParam,
  1823.             CWnd::FromHandle((HWND)lParam),
  1824.             CWnd::FromHandle((HWND)wParam));
  1825.         break;
  1826.  
  1827.     case AfxSig_vD:
  1828.         (this->*mmf.pfn_vD)(CDC::FromHandle((HDC)wParam));
  1829.         break;
  1830.  
  1831.     case AfxSig_vM:
  1832.         (this->*mmf.pfn_vM)(CMenu::FromHandle((HMENU)wParam));
  1833.         break;
  1834.  
  1835.     case AfxSig_vMwb:
  1836.         (this->*mmf.pfn_vMwb)(CMenu::FromHandle((HMENU)wParam),
  1837.             LOWORD(lParam), (BOOL)HIWORD(lParam));
  1838.         break;
  1839.  
  1840.     case AfxSig_vW:
  1841.         (this->*mmf.pfn_vW)(CWnd::FromHandle((HWND)wParam));
  1842.         break;
  1843.  
  1844.     case AfxSig_vW2:
  1845.         (this->*mmf.pfn_vW)(CWnd::FromHandle((HWND)lParam));
  1846.         break;
  1847.  
  1848.     case AfxSig_vWww:
  1849.         (this->*mmf.pfn_vWww)(CWnd::FromHandle((HWND)wParam), LOWORD(lParam),
  1850.             HIWORD(lParam));
  1851.         break;
  1852.  
  1853.     case AfxSig_vWp:
  1854.         {
  1855.             CPoint point((DWORD)lParam);
  1856.             (this->*mmf.pfn_vWp)(CWnd::FromHandle((HWND)wParam), point);
  1857.         }
  1858.         break;
  1859.  
  1860.     case AfxSig_vWh:
  1861.         (this->*mmf.pfn_vWh)(CWnd::FromHandle((HWND)wParam),
  1862.                 (HANDLE)lParam);
  1863.         break;
  1864.  
  1865.     case AfxSig_vwW:
  1866.         (this->*mmf.pfn_vwW)(wParam, CWnd::FromHandle((HWND)lParam));
  1867.         break;
  1868.  
  1869.     case AfxSig_vwWb:
  1870.         (this->*mmf.pfn_vwWb)((UINT)(LOWORD(wParam)),
  1871.             CWnd::FromHandle((HWND)lParam), (BOOL)HIWORD(wParam));
  1872.         break;
  1873.  
  1874.     case AfxSig_vwwW:
  1875.     case AfxSig_vwwx:
  1876.         {
  1877.             // special case for WM_VSCROLL and WM_HSCROLL
  1878.             ASSERT(message == WM_VSCROLL || message == WM_HSCROLL ||
  1879.                 message == WM_VSCROLL+WM_REFLECT_BASE || message == WM_HSCROLL+WM_REFLECT_BASE);
  1880.             int nScrollCode = (short)LOWORD(wParam);
  1881.             int nPos = (short)HIWORD(wParam);
  1882.             if (lpEntry->nSig == AfxSig_vwwW)
  1883.                 (this->*mmf.pfn_vwwW)(nScrollCode, nPos,
  1884.                     CWnd::FromHandle((HWND)lParam));
  1885.             else
  1886.                 (this->*mmf.pfn_vwwx)(nScrollCode, nPos);
  1887.         }
  1888.         break;
  1889.  
  1890.     case AfxSig_vs:
  1891.         (this->*mmf.pfn_vs)((LPTSTR)lParam);
  1892.         break;
  1893.  
  1894.     case AfxSig_vws:
  1895.         (this->*mmf.pfn_vws)((UINT) wParam, (LPCTSTR)lParam);
  1896.         break;
  1897.  
  1898.     case AfxSig_vOWNER:
  1899.         (this->*mmf.pfn_vOWNER)((int)wParam, (LPTSTR)lParam);
  1900.         lResult = TRUE;
  1901.         break;
  1902.  
  1903.     case AfxSig_iis:
  1904.         lResult = (this->*mmf.pfn_iis)((int)wParam, (LPTSTR)lParam);
  1905.         break;
  1906.  
  1907.     case AfxSig_wp:
  1908.         {
  1909.             CPoint point((DWORD)lParam);
  1910.             lResult = (this->*mmf.pfn_wp)(point);
  1911.         }
  1912.         break;
  1913.  
  1914.     case AfxSig_wv: // AfxSig_bv, AfxSig_wv
  1915.         lResult = (this->*mmf.pfn_wv)();
  1916.         break;
  1917.  
  1918.     case AfxSig_vCALC:
  1919.         (this->*mmf.pfn_vCALC)((BOOL)wParam, (NCCALCSIZE_PARAMS*)lParam);
  1920.         break;
  1921.  
  1922.     case AfxSig_vPOS:
  1923.         (this->*mmf.pfn_vPOS)((WINDOWPOS*)lParam);
  1924.         break;
  1925.  
  1926.     case AfxSig_vwwh:
  1927.         (this->*mmf.pfn_vwwh)(LOWORD(wParam), HIWORD(wParam), (HANDLE)lParam);
  1928.         break;
  1929.  
  1930.     case AfxSig_vwp:
  1931.         {
  1932.             CPoint point((DWORD)lParam);
  1933.             (this->*mmf.pfn_vwp)(wParam, point);
  1934.             break;
  1935.         }
  1936.     case AfxSig_vwSIZING:
  1937.         (this->*mmf.pfn_vwl)(wParam, lParam);
  1938.         lResult = TRUE;
  1939.         break;
  1940.  
  1941.     case AfxSig_bwsp:
  1942.         lResult = (this->*mmf.pfn_bwsp)(LOWORD(wParam), (short) HIWORD(wParam),
  1943.             CPoint(LOWORD(lParam), HIWORD(lParam)));
  1944.         if (!lResult)
  1945.             return FALSE;
  1946.     }
  1947.     goto LReturnTrue;
  1948.  
  1949. LDispatchRegistered:    // for registered windows messages
  1950.     ASSERT(message >= 0xC000);
  1951.     mmf.pfn = lpEntry->pfn;
  1952.     lResult = (this->*mmf.pfn_lwl)(wParam, lParam);
  1953.  
  1954. LReturnTrue:
  1955.     if (pResult != NULL)
  1956.         *pResult = lResult;
  1957.     return TRUE;
  1958. }
  1959.  
  1960. /////////////////////////////////////////////////////////////////////////////
  1961. // CTestCmdUI - used to test for disabled commands before dispatching
  1962.  
  1963. class CTestCmdUI : public CCmdUI
  1964. {
  1965. public:
  1966.     CTestCmdUI();
  1967.  
  1968. public: // re-implementations only
  1969.     virtual void Enable(BOOL bOn);
  1970.     virtual void SetCheck(int nCheck);
  1971.     virtual void SetRadio(BOOL bOn);
  1972.     virtual void SetText(LPCTSTR);
  1973.  
  1974.     BOOL m_bEnabled;
  1975. };
  1976.  
  1977. CTestCmdUI::CTestCmdUI()
  1978. {
  1979.     m_bEnabled = TRUE;  // assume it is enabled
  1980. }
  1981.  
  1982. void CTestCmdUI::Enable(BOOL bOn)
  1983. {
  1984.     m_bEnabled = bOn;
  1985.     m_bEnableChanged = TRUE;
  1986. }
  1987.  
  1988. void CTestCmdUI::SetCheck(int)
  1989. {
  1990.     // do nothing -- just want to know about calls to Enable
  1991. }
  1992.  
  1993. void CTestCmdUI::SetRadio(BOOL)
  1994. {
  1995.     // do nothing -- just want to know about calls to Enable
  1996. }
  1997.  
  1998. void CTestCmdUI::SetText(LPCTSTR)
  1999. {
  2000.     // do nothing -- just want to know about calls to Enable
  2001. }
  2002.  
  2003. /////////////////////////////////////////////////////////////////////////////
  2004. // CWnd command handling
  2005.  
  2006. BOOL CWnd::OnCommand(WPARAM wParam, LPARAM lParam)
  2007.     // return TRUE if command invocation was attempted
  2008. {
  2009.     UINT nID = LOWORD(wParam);
  2010.     HWND hWndCtrl = (HWND)lParam;
  2011.     int nCode = HIWORD(wParam);
  2012.  
  2013.     // default routing for command messages (through closure table)
  2014.  
  2015.     if (hWndCtrl == NULL)
  2016.     {
  2017.         // zero IDs for normal commands are not allowed
  2018.         if (nID == 0)
  2019.             return FALSE;
  2020.  
  2021.         // make sure command has not become disabled before routing
  2022.         CTestCmdUI state;
  2023.         state.m_nID = nID;
  2024.         OnCmdMsg(nID, CN_UPDATE_COMMAND_UI, &state, NULL);
  2025.         if (!state.m_bEnabled)
  2026.         {
  2027.             TRACE1("Warning: not executing disabled command %d\n", nID);
  2028.             return TRUE;
  2029.         }
  2030.  
  2031.         // menu or accelerator
  2032.         nCode = CN_COMMAND;
  2033.     }
  2034.     else
  2035.     {
  2036.         // control notification
  2037.         ASSERT(nID == 0 || ::IsWindow(hWndCtrl));
  2038.  
  2039.         if (_afxThreadState->m_hLockoutNotifyWindow == m_hWnd)
  2040.             return TRUE;        // locked out - ignore control notification
  2041.  
  2042.         // reflect notification to child window control
  2043.         if (ReflectLastMsg(hWndCtrl))
  2044.             return TRUE;    // eaten by child
  2045.  
  2046.         // zero IDs for normal commands are not allowed
  2047.         if (nID == 0)
  2048.             return FALSE;
  2049.     }
  2050.  
  2051. #ifdef _DEBUG
  2052.     if (nCode < 0 && nCode != (int)0x8000)
  2053.         TRACE1("Implementation Warning: control notification = $%X.\n",
  2054.             nCode);
  2055. #endif
  2056.  
  2057.     return OnCmdMsg(nID, nCode, NULL, NULL);
  2058. }
  2059.  
  2060. BOOL CWnd::OnNotify(WPARAM, LPARAM lParam, LRESULT* pResult)
  2061. {
  2062.     ASSERT(pResult != NULL);
  2063.     NMHDR* pNMHDR = (NMHDR*)lParam;
  2064.     HWND hWndCtrl = pNMHDR->hwndFrom;
  2065.  
  2066.     // get the child ID from the window itself
  2067.     UINT nID = _AfxGetDlgCtrlID(hWndCtrl);
  2068.     int nCode = pNMHDR->code;
  2069.  
  2070.     ASSERT(hWndCtrl != NULL);
  2071.     ASSERT(::IsWindow(hWndCtrl));
  2072.  
  2073.     if (_afxThreadState->m_hLockoutNotifyWindow == m_hWnd)
  2074.         return TRUE;        // locked out - ignore control notification
  2075.  
  2076.     // reflect notification to child window control
  2077.     if (ReflectLastMsg(hWndCtrl, pResult))
  2078.         return TRUE;        // eaten by child
  2079.  
  2080.     AFX_NOTIFY notify;
  2081.     notify.pResult = pResult;
  2082.     notify.pNMHDR = pNMHDR;
  2083.     return OnCmdMsg(nID, MAKELONG(nCode, WM_NOTIFY), ¬ify, NULL);
  2084. }
  2085.  
  2086. /////////////////////////////////////////////////////////////////////////////
  2087. // CWnd extensions
  2088.  
  2089. CFrameWnd* CWnd::GetParentFrame() const
  2090. {
  2091.     if (GetSafeHwnd() == NULL) // no Window attached
  2092.         return NULL;
  2093.  
  2094.     ASSERT_VALID(this);
  2095.  
  2096.     CWnd* pParentWnd = GetParent();  // start with one parent up
  2097.     while (pParentWnd != NULL)
  2098.     {
  2099.         if (pParentWnd->IsFrameWnd())
  2100.             return (CFrameWnd*)pParentWnd;
  2101.         pParentWnd = pParentWnd->GetParent();
  2102.     }
  2103.     return NULL;
  2104. }
  2105.  
  2106. HWND AFXAPI AfxGetParentOwner(HWND hWnd)
  2107. {
  2108.     // check for permanent-owned window first
  2109.     CWnd* pWnd = CWnd::FromHandlePermanent(hWnd);
  2110.     if (pWnd != NULL)
  2111.         return pWnd->GetOwner()->GetSafeHwnd();
  2112.  
  2113.     // otherwise, return parent in the Windows sense
  2114.     return (::GetWindowLong(hWnd, GWL_STYLE) & WS_CHILD) ?
  2115.         ::GetParent(hWnd) : ::GetWindow(hWnd, GW_OWNER);
  2116. }
  2117.  
  2118. CWnd* CWnd::GetTopLevelParent() const
  2119. {
  2120.     if (GetSafeHwnd() == NULL) // no Window attached
  2121.         return NULL;
  2122.  
  2123.     ASSERT_VALID(this);
  2124.  
  2125.     HWND hWndParent = m_hWnd;
  2126.     HWND hWndT;
  2127.     while ((hWndT = AfxGetParentOwner(hWndParent)) != NULL)
  2128.         hWndParent = hWndT;
  2129.  
  2130.     return CWnd::FromHandle(hWndParent);
  2131. }
  2132.  
  2133. CWnd* CWnd::GetTopLevelOwner() const
  2134. {
  2135.     if (GetSafeHwnd() == NULL) // no Window attached
  2136.         return NULL;
  2137.  
  2138.     ASSERT_VALID(this);
  2139.  
  2140.     HWND hWndOwner = m_hWnd;
  2141.     HWND hWndT;
  2142.     while ((hWndT = ::GetWindow(hWndOwner, GW_OWNER)) != NULL)
  2143.         hWndOwner = hWndT;
  2144.  
  2145.     return CWnd::FromHandle(hWndOwner);
  2146. }
  2147.  
  2148. CWnd* CWnd::GetParentOwner() const
  2149. {
  2150.     if (GetSafeHwnd() == NULL) // no Window attached
  2151.         return NULL;
  2152.  
  2153.     ASSERT_VALID(this);
  2154.  
  2155.     HWND hWndParent = m_hWnd;
  2156.     HWND hWndT;
  2157.     while ((::GetWindowLong(hWndParent, GWL_STYLE) & WS_CHILD) &&
  2158.         (hWndT = ::GetParent(hWndParent)) != NULL)
  2159.     {
  2160.         hWndParent = hWndT;
  2161.     }
  2162.  
  2163.     return CWnd::FromHandle(hWndParent);
  2164. }
  2165.  
  2166. BOOL CWnd::IsTopParentActive() const
  2167. {
  2168.     ASSERT(m_hWnd != NULL);
  2169.     ASSERT_VALID(this);
  2170.  
  2171.     return CWnd::GetForegroundWindow() ==
  2172.         GetTopLevelParent()->GetLastActivePopup();
  2173. }
  2174.  
  2175. void CWnd::ActivateTopParent()
  2176. {
  2177.     // special activate logic for floating toolbars and palettes
  2178.     CWnd* pTopLevel = GetTopLevelParent();
  2179.     CWnd* pActiveWnd = GetForegroundWindow();
  2180.     if (pActiveWnd == NULL ||
  2181.         !(pActiveWnd->m_hWnd == m_hWnd || ::IsChild(pActiveWnd->m_hWnd, m_hWnd)))
  2182.     {
  2183.         // clicking on floating frame when it does not have
  2184.         // focus itself -- activate the toplevel frame instead.
  2185.         pTopLevel->SetForegroundWindow();
  2186.     }
  2187. }
  2188.  
  2189. CFrameWnd* CWnd::GetTopLevelFrame() const
  2190. {
  2191.     if (GetSafeHwnd() == NULL) // no Window attached
  2192.         return NULL;
  2193.  
  2194.     ASSERT_VALID(this);
  2195.  
  2196.     CFrameWnd* pFrameWnd = (CFrameWnd*)this;
  2197.     if (!IsFrameWnd())
  2198.         pFrameWnd = GetParentFrame();
  2199.  
  2200.     if (pFrameWnd != NULL)
  2201.     {
  2202.         CFrameWnd* pTemp;
  2203.         while ((pTemp = pFrameWnd->GetParentFrame()) != NULL)
  2204.             pFrameWnd = pTemp;
  2205.     }
  2206.     return pFrameWnd;
  2207. }
  2208.  
  2209. CWnd* PASCAL CWnd::GetSafeOwner(CWnd* pParent, HWND* pWndTop)
  2210. {
  2211.     // get window to start with
  2212.     HWND hWnd = pParent->GetSafeHwnd();
  2213.     if (hWnd == NULL)
  2214.         hWnd = AfxGetMainWnd()->GetSafeHwnd();
  2215.  
  2216.     // a popup window cannot be owned by a child window
  2217.     while (hWnd != NULL && (::GetWindowLong(hWnd, GWL_STYLE) & WS_CHILD))
  2218.         hWnd = ::GetParent(hWnd);
  2219.  
  2220.     // determine toplevel window to disable as well
  2221.     HWND hWndTop = hWnd, hWndTemp = hWnd;
  2222.     for (;;)
  2223.     {
  2224.         if (hWndTemp == NULL)
  2225.             break;
  2226.         else
  2227.             hWndTop = hWndTemp;
  2228.         hWndTemp = ::GetParent(hWndTop);
  2229.     }
  2230.  
  2231.     // get last active popup of first non-child that was found
  2232.     if (pParent == NULL && hWnd != NULL)
  2233.         hWnd = ::GetLastActivePopup(hWnd);
  2234.  
  2235.     // disable and store top level parent window if specified
  2236.     if (pWndTop != NULL)
  2237.     {
  2238.         if (hWndTop != NULL && ::IsWindowEnabled(hWndTop) && hWndTop != hWnd)
  2239.         {
  2240.             *pWndTop = hWndTop;
  2241.             ::EnableWindow(hWndTop, FALSE);
  2242.         }
  2243.         else
  2244.             *pWndTop = NULL;
  2245.     }
  2246.  
  2247.     // return it as CWnd* (may be temporary object)
  2248.     CWnd* pWnd = CWnd::FromHandle(hWnd);
  2249.     return pWnd;
  2250. }
  2251.  
  2252. CWnd* PASCAL CWnd::GetDescendantWindow(HWND hWnd, int nID, BOOL bOnlyPerm)
  2253. {
  2254.     // GetDlgItem recursive (return first found)
  2255.     // breadth-first for 1 level, then depth-first for next level
  2256.  
  2257.     // use GetDlgItem since it is a fast USER function
  2258.     HWND hWndChild;
  2259.     CWnd* pWndChild;
  2260.     if ((hWndChild = ::GetDlgItem(hWnd, nID)) != NULL)
  2261.     {
  2262.         if (::GetTopWindow(hWndChild) != NULL)
  2263.         {
  2264.             // children with the same ID as their parent have priority
  2265.             pWndChild = GetDescendantWindow(hWndChild, nID, bOnlyPerm);
  2266.             if (pWndChild != NULL)
  2267.                 return pWndChild;
  2268.         }
  2269.         // return temporary handle if allowed
  2270.         if (!bOnlyPerm)
  2271.             return CWnd::FromHandle(hWndChild);
  2272.  
  2273.         // return only permanent handle
  2274.         pWndChild = CWnd::FromHandlePermanent(hWndChild);
  2275.         if (pWndChild != NULL)
  2276.             return pWndChild;
  2277.     }
  2278.  
  2279.     // walk each child
  2280.     for (hWndChild = ::GetTopWindow(hWnd); hWndChild != NULL;
  2281.         hWndChild = ::GetNextWindow(hWndChild, GW_HWNDNEXT))
  2282.     {
  2283.         pWndChild = GetDescendantWindow(hWndChild, nID, bOnlyPerm);
  2284.         if (pWndChild != NULL)
  2285.             return pWndChild;
  2286.     }
  2287.     return NULL;    // not found
  2288. }
  2289.  
  2290. void PASCAL CWnd::SendMessageToDescendants(HWND hWnd, UINT message,
  2291.     WPARAM wParam, LPARAM lParam, BOOL bDeep, BOOL bOnlyPerm)
  2292. {
  2293.     // walk through HWNDs to avoid creating temporary CWnd objects
  2294.     // unless we need to call this function recursively
  2295.     for (HWND hWndChild = ::GetTopWindow(hWnd); hWndChild != NULL;
  2296.         hWndChild = ::GetNextWindow(hWndChild, GW_HWNDNEXT))
  2297.     {
  2298.         // if bOnlyPerm is TRUE, don't send to non-permanent windows
  2299.         if (bOnlyPerm)
  2300.         {
  2301.             CWnd* pWnd = CWnd::FromHandlePermanent(hWndChild);
  2302.             if (pWnd != NULL)
  2303.             {
  2304.                 // call window proc directly since it is a C++ window
  2305.                 AfxCallWndProc(pWnd, pWnd->m_hWnd, message, wParam, lParam);
  2306.             }
  2307.         }
  2308.         else
  2309.         {
  2310.             // send message with Windows SendMessage API
  2311.             ::SendMessage(hWndChild, message, wParam, lParam);
  2312.         }
  2313.         if (bDeep && ::GetTopWindow(hWndChild) != NULL)
  2314.         {
  2315.             // send to child windows after parent
  2316.             SendMessageToDescendants(hWndChild, message, wParam, lParam,
  2317.                 bDeep, bOnlyPerm);
  2318.         }
  2319.     }
  2320. }
  2321.  
  2322. /////////////////////////////////////////////////////////////////////////////
  2323. // Scroll bar helpers
  2324. //  hook for CWnd functions
  2325. //    only works for derived class (eg: CView) that override 'GetScrollBarCtrl'
  2326. // if the window doesn't have a _visible_ windows scrollbar - then
  2327. //   look for a sibling with the appropriate ID
  2328.  
  2329. CScrollBar* CWnd::GetScrollBarCtrl(int) const
  2330. {
  2331.     return NULL;        // no special scrollers supported
  2332. }
  2333.  
  2334. int CWnd::SetScrollPos(int nBar, int nPos, BOOL bRedraw)
  2335. {
  2336.     CScrollBar* pScrollBar;
  2337.     if ((pScrollBar = GetScrollBarCtrl(nBar)) != NULL)
  2338.         return pScrollBar->SetScrollPos(nPos, bRedraw);
  2339.     else
  2340.         return ::SetScrollPos(m_hWnd, nBar, nPos, bRedraw);
  2341. }
  2342.  
  2343. int CWnd::GetScrollPos(int nBar) const
  2344. {
  2345.     CScrollBar* pScrollBar;
  2346.     if ((pScrollBar = GetScrollBarCtrl(nBar)) != NULL)
  2347.         return pScrollBar->GetScrollPos();
  2348.     else
  2349.         return ::GetScrollPos(m_hWnd, nBar);
  2350. }
  2351.  
  2352. void CWnd::SetScrollRange(int nBar, int nMinPos, int nMaxPos, BOOL bRedraw)
  2353. {
  2354.     CScrollBar* pScrollBar;
  2355.     if ((pScrollBar = GetScrollBarCtrl(nBar)) != NULL)
  2356.         pScrollBar->SetScrollRange(nMinPos, nMaxPos, bRedraw);
  2357.     else
  2358.         ::SetScrollRange(m_hWnd, nBar, nMinPos, nMaxPos, bRedraw);
  2359. }
  2360.  
  2361. void CWnd::GetScrollRange(int nBar, LPINT lpMinPos, LPINT lpMaxPos) const
  2362. {
  2363.     CScrollBar* pScrollBar;
  2364.     if ((pScrollBar = GetScrollBarCtrl(nBar)) != NULL)
  2365.         pScrollBar->GetScrollRange(lpMinPos, lpMaxPos);
  2366.     else
  2367.         ::GetScrollRange(m_hWnd, nBar, lpMinPos, lpMaxPos);
  2368. }
  2369.  
  2370. // Turn on/off non-control scrollbars
  2371. //   for WS_?SCROLL scrollbars - show/hide them
  2372. //   for control scrollbar - enable/disable them
  2373. void CWnd::EnableScrollBarCtrl(int nBar, BOOL bEnable)
  2374. {
  2375.     CScrollBar* pScrollBar;
  2376.     if (nBar == SB_BOTH)
  2377.     {
  2378.         EnableScrollBarCtrl(SB_HORZ, bEnable);
  2379.         EnableScrollBarCtrl(SB_VERT, bEnable);
  2380.     }
  2381.     else if ((pScrollBar = GetScrollBarCtrl(nBar)) != NULL)
  2382.     {
  2383.         // control scrollbar - enable or disable
  2384.         pScrollBar->EnableWindow(bEnable);
  2385.     }
  2386.     else
  2387.     {
  2388.         // WS_?SCROLL scrollbar - show or hide
  2389.         ShowScrollBar(nBar, bEnable);
  2390.     }
  2391. }
  2392.  
  2393. BOOL CWnd::SetScrollInfo(int nBar, LPSCROLLINFO lpScrollInfo, BOOL bRedraw)
  2394. {
  2395.     ASSERT(lpScrollInfo != NULL);
  2396.     if (afxData.nWinVer < 0x333)
  2397.         return FALSE;
  2398.  
  2399.     HWND hWnd = m_hWnd;
  2400.     CScrollBar* pScrollBar;
  2401.     if (nBar != SB_CTL && (pScrollBar = GetScrollBarCtrl(nBar)) != NULL)
  2402.     {
  2403.         hWnd = pScrollBar->m_hWnd;
  2404.         nBar = SB_CTL;
  2405.     }
  2406.     lpScrollInfo->cbSize = sizeof(*lpScrollInfo);
  2407.     ::SetScrollInfo(hWnd, nBar, lpScrollInfo, bRedraw);
  2408.     return TRUE;
  2409. }
  2410.  
  2411. BOOL CWnd::GetScrollInfo(int nBar, LPSCROLLINFO lpScrollInfo, UINT nMask)
  2412. {
  2413.     ASSERT(lpScrollInfo != NULL);
  2414.     if (afxData.nWinVer < 0x333)
  2415.         return FALSE;
  2416.  
  2417.     HWND hWnd = m_hWnd;
  2418.     CScrollBar* pScrollBar;
  2419.     if (nBar != SB_CTL && (pScrollBar = GetScrollBarCtrl(nBar)) != NULL)
  2420.     {
  2421.         hWnd = pScrollBar->m_hWnd;
  2422.         nBar = SB_CTL;
  2423.     }
  2424.     lpScrollInfo->cbSize = sizeof(*lpScrollInfo);
  2425.     lpScrollInfo->fMask = nMask;
  2426.     return ::GetScrollInfo(hWnd, nBar, lpScrollInfo);
  2427. }
  2428.  
  2429. int CWnd::GetScrollLimit(int nBar)
  2430. {
  2431.     int nMin, nMax;
  2432.     GetScrollRange(nBar, &nMin, &nMax);
  2433.     SCROLLINFO info;
  2434.     if (GetScrollInfo(nBar, &info, SIF_PAGE))
  2435.     {
  2436.         nMax -= __max(info.nPage-1,0);
  2437.     }
  2438.     return nMax;
  2439. }
  2440.  
  2441. void CWnd::ScrollWindow(int xAmount, int yAmount,
  2442.     LPCRECT lpRect, LPCRECT lpClipRect)
  2443. {
  2444.     ASSERT(::IsWindow(m_hWnd));
  2445.  
  2446.     if (IsWindowVisible() || lpRect != NULL || lpClipRect != NULL)
  2447.     {
  2448.         // When visible, let Windows do the scrolling
  2449.         ::ScrollWindow(m_hWnd, xAmount, yAmount, lpRect, lpClipRect);
  2450.     }
  2451.     else
  2452.     {
  2453.         // Windows does not perform any scrolling if the window is
  2454.         // not visible.  This leaves child windows unscrolled.
  2455.         // To account for this oversight, the child windows are moved
  2456.         // directly instead.
  2457.         HWND hWndChild = ::GetWindow(m_hWnd, GW_CHILD);
  2458.         if (hWndChild != NULL)
  2459.         {
  2460.             for (; hWndChild != NULL;
  2461.                 hWndChild = ::GetNextWindow(hWndChild, GW_HWNDNEXT))
  2462.             {
  2463.                 CRect rect;
  2464.                 ::GetWindowRect(hWndChild, &rect);
  2465.                 ScreenToClient(&rect);
  2466.                 ::SetWindowPos(hWndChild, NULL,
  2467.                     rect.left+xAmount, rect.top+yAmount, 0, 0,
  2468.                     SWP_NOSIZE|SWP_NOACTIVATE|SWP_NOZORDER);
  2469.             }
  2470.         }
  2471.     }
  2472.  
  2473. #ifndef _AFX_NO_OCC_SUPPORT
  2474.  
  2475.     if ((m_pCtrlCont == NULL) || (lpRect != NULL))
  2476.         return;
  2477.  
  2478.     // the following code is for OLE control containers only
  2479.  
  2480.     m_pCtrlCont->ScrollChildren(xAmount, yAmount);
  2481.  
  2482. #endif // !_AFX_NO_OCC_SUPPORT
  2483. }
  2484.  
  2485. /////////////////////////////////////////////////////////////////////////////
  2486. // minimal layout support
  2487.  
  2488. void CWnd::RepositionBars(UINT nIDFirst, UINT nIDLast, UINT nIDLeftOver,
  2489.     UINT nFlags, LPRECT lpRectParam, LPCRECT lpRectClient, BOOL bStretch)
  2490. {
  2491.     ASSERT(nFlags == 0 || nFlags == reposQuery || nFlags == reposExtra);
  2492.  
  2493.     // walk kids in order, control bars get the resize notification
  2494.     //   which allow them to shrink the client area
  2495.     // remaining size goes to the 'nIDLeftOver' pane
  2496.     // NOTE: nIDFirst->nIDLast are usually 0->0xffff
  2497.  
  2498.     AFX_SIZEPARENTPARAMS layout;
  2499.     HWND hWndLeftOver = NULL;
  2500.  
  2501.     layout.bStretch = bStretch;
  2502.     layout.sizeTotal.cx = layout.sizeTotal.cy = 0;
  2503.     if (lpRectClient != NULL)
  2504.         layout.rect = *lpRectClient;    // starting rect comes from parameter
  2505.     else
  2506.         GetClientRect(&layout.rect);    // starting rect comes from client rect
  2507.  
  2508.     if (nFlags != reposQuery)
  2509.         layout.hDWP = ::BeginDeferWindowPos(8); // reasonable guess
  2510.     else
  2511.         layout.hDWP = NULL; // not actually doing layout
  2512.  
  2513.     for (HWND hWndChild = ::GetTopWindow(m_hWnd); hWndChild != NULL;
  2514.         hWndChild = ::GetNextWindow(hWndChild, GW_HWNDNEXT))
  2515.     {
  2516.         UINT nIDC = _AfxGetDlgCtrlID(hWndChild);
  2517.         CWnd* pWnd = CWnd::FromHandlePermanent(hWndChild);
  2518.         if (nIDC == nIDLeftOver)
  2519.             hWndLeftOver = hWndChild;
  2520.         else if (nIDC >= nIDFirst && nIDC <= nIDLast && pWnd != NULL)
  2521.             ::SendMessage(hWndChild, WM_SIZEPARENT, 0, (LPARAM)&layout);
  2522.     }
  2523.  
  2524.     // if just getting the available rectangle, return it now...
  2525.     if (nFlags == reposQuery)
  2526.     {
  2527.         ASSERT(lpRectParam != NULL);
  2528.         if (bStretch)
  2529.             ::CopyRect(lpRectParam, &layout.rect);
  2530.         else
  2531.         {
  2532.             lpRectParam->left = lpRectParam->top = 0;
  2533.             lpRectParam->right = layout.sizeTotal.cx;
  2534.             lpRectParam->bottom = layout.sizeTotal.cy;
  2535.         }
  2536.         return;
  2537.     }
  2538.  
  2539.     // the rest is the client size of the left-over pane
  2540.     if (nIDLeftOver != 0 && hWndLeftOver != NULL)
  2541.     {
  2542.         CWnd* pLeftOver = CWnd::FromHandle(hWndLeftOver);
  2543.         // allow extra space as specified by lpRectBorder
  2544. #ifndef _MAC
  2545.         if (nFlags == reposExtra)
  2546. #else
  2547.         // don't subtract border from SDI frame window
  2548.         if (nFlags == reposExtra &&
  2549.             GetTopLevelFrame()->GetActiveView() == NULL)
  2550. #endif
  2551.         {
  2552.             ASSERT(lpRectParam != NULL);
  2553.             layout.rect.left += lpRectParam->left;
  2554.             layout.rect.top += lpRectParam->top;
  2555.             layout.rect.right -= lpRectParam->right;
  2556.             layout.rect.bottom -= lpRectParam->bottom;
  2557.         }
  2558.         // reposition the window
  2559.         pLeftOver->CalcWindowRect(&layout.rect);
  2560.         AfxRepositionWindow(&layout, hWndLeftOver, &layout.rect);
  2561. #ifdef _MAC
  2562.         // On the Macintosh, we want the MDI client window to be at the bottom
  2563.         // of the Z-order, so that bar windows remain "on top"
  2564.         if ((GetExStyle() & WS_EX_MDICLIENT) != 0)
  2565.         {
  2566.             layout.hDWP = ::DeferWindowPos(layout.hDWP, hWndLeftOver,
  2567.                 HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
  2568.         }
  2569. #endif
  2570.     }
  2571.  
  2572.     // move and resize all the windows at once!
  2573.     if (layout.hDWP == NULL || !::EndDeferWindowPos(layout.hDWP))
  2574.         TRACE0("Warning: DeferWindowPos failed - low system resources.\n");
  2575. }
  2576.  
  2577. void AFXAPI AfxRepositionWindow(AFX_SIZEPARENTPARAMS* lpLayout,
  2578.     HWND hWnd, LPCRECT lpRect)
  2579. {
  2580.     ASSERT(hWnd != NULL);
  2581.     ASSERT(lpRect != NULL);
  2582.     HWND hWndParent = ::GetParent(hWnd);
  2583.     ASSERT(hWndParent != NULL);
  2584.  
  2585.     if (lpLayout != NULL && lpLayout->hDWP == NULL)
  2586.         return;
  2587.  
  2588.     // first check if the new rectangle is the same as the current
  2589.     CRect rectOld;
  2590.     ::GetWindowRect(hWnd, rectOld);
  2591.     ::ScreenToClient(hWndParent, &rectOld.TopLeft());
  2592.     ::ScreenToClient(hWndParent, &rectOld.BottomRight());
  2593.     if (_AfxIdenticalRect(rectOld, lpRect))
  2594.         return;     // nothing to do
  2595.  
  2596.     // try to use DeferWindowPos for speed, otherwise use SetWindowPos
  2597.     if (lpLayout != NULL)
  2598.     {
  2599.         lpLayout->hDWP = ::DeferWindowPos(lpLayout->hDWP, hWnd, NULL,
  2600.             lpRect->left, lpRect->top,  lpRect->right - lpRect->left,
  2601.             lpRect->bottom - lpRect->top, SWP_NOACTIVATE|SWP_NOZORDER);
  2602.     }
  2603.     else
  2604.     {
  2605.         ::SetWindowPos(hWnd, NULL, lpRect->left, lpRect->top,
  2606.             lpRect->right - lpRect->left, lpRect->bottom - lpRect->top,
  2607.             SWP_NOACTIVATE|SWP_NOZORDER);
  2608.     }
  2609. }
  2610.  
  2611. void CWnd::CalcWindowRect(LPRECT lpClientRect, UINT nAdjustType)
  2612. {
  2613.     DWORD dwExStyle = GetExStyle();
  2614.     if (nAdjustType == 0)
  2615.         dwExStyle &= ~WS_EX_CLIENTEDGE;
  2616.     ::AdjustWindowRectEx(lpClientRect, GetStyle(), FALSE, dwExStyle);
  2617. }
  2618.  
  2619. /////////////////////////////////////////////////////////////////////////////
  2620. // Special keyboard/system command processing
  2621.  
  2622. BOOL CWnd::HandleFloatingSysCommand(UINT nID, LPARAM lParam)
  2623. {
  2624.     CWnd* pParent = GetTopLevelParent();
  2625.     switch (nID & 0xfff0)
  2626.     {
  2627.     case SC_PREVWINDOW:
  2628.     case SC_NEXTWINDOW:
  2629.         if (LOWORD(lParam) == VK_F6 && pParent != NULL)
  2630.         {
  2631.             pParent->SetFocus();
  2632.             return TRUE;
  2633.         }
  2634.         break;
  2635.  
  2636.     case SC_CLOSE:
  2637.     case SC_KEYMENU:
  2638.         // Check lParam.  If it is 0L, then the user may have done
  2639.         // an Alt+Tab, so just ignore it.  This breaks the ability to
  2640.         // just press the Alt-key and have the first menu selected,
  2641.         // but this is minor compared to what happens in the Alt+Tab
  2642.         // case.
  2643.         if ((nID & 0xfff0) == SC_CLOSE || lParam != 0L)
  2644.         {
  2645.             if (pParent != NULL)
  2646.             {
  2647.                 // Sending the above WM_SYSCOMMAND may destroy the app,
  2648.                 // so we have to be careful about restoring activation
  2649.                 // and focus after sending it.
  2650.                 HWND hWndSave = m_hWnd;
  2651.                 HWND hWndFocus = ::GetFocus();
  2652.                 pParent->SetActiveWindow();
  2653.                 pParent->SendMessage(WM_SYSCOMMAND, nID, lParam);
  2654.  
  2655.                 // be very careful here...
  2656.                 if (::IsWindow(hWndSave))
  2657.                     ::SetActiveWindow(hWndSave);
  2658.                 if (::IsWindow(hWndFocus))
  2659.                     ::SetFocus(hWndFocus);
  2660.             }
  2661.         }
  2662.         return TRUE;
  2663.     }
  2664.     return FALSE;
  2665. }
  2666.  
  2667. BOOL PASCAL CWnd::WalkPreTranslateTree(HWND hWndStop, MSG* pMsg)
  2668. {
  2669.     ASSERT(hWndStop == NULL || ::IsWindow(hWndStop));
  2670.     ASSERT(pMsg != NULL);
  2671.  
  2672.     // walk from the target window up to the hWndStop window checking
  2673.     //  if any window wants to translate this message
  2674.  
  2675.     for (HWND hWnd = pMsg->hwnd; hWnd != NULL; hWnd = ::GetParent(hWnd))
  2676.     {
  2677.         CWnd* pWnd = CWnd::FromHandlePermanent(hWnd);
  2678.         if (pWnd != NULL)
  2679.         {
  2680.             // target window is a C++ window
  2681.             if (pWnd->PreTranslateMessage(pMsg))
  2682.                 return TRUE; // trapped by target window (eg: accelerators)
  2683.         }
  2684.  
  2685.         // got to hWndStop window without interest
  2686.         if (hWnd == hWndStop)
  2687.             break;
  2688.     }
  2689.     return FALSE;       // no special processing
  2690. }
  2691.  
  2692. BOOL CWnd::SendChildNotifyLastMsg(LRESULT* pResult)
  2693. {
  2694.     _AFX_THREAD_STATE* pThreadState = _afxThreadState.GetData();
  2695.     return OnChildNotify(pThreadState->m_lastSentMsg.message,
  2696.         pThreadState->m_lastSentMsg.wParam, pThreadState->m_lastSentMsg.lParam, pResult);
  2697. }
  2698.  
  2699. BOOL PASCAL CWnd::ReflectLastMsg(HWND hWndChild, LRESULT* pResult)
  2700. {
  2701.     // get the map, and if no map, then this message does not need reflection
  2702.     CHandleMap* pMap = afxMapHWND();
  2703.     if (pMap == NULL)
  2704.         return FALSE;
  2705.  
  2706.     // check if in permanent map, if it is reflect it (could be OLE control)
  2707.     CWnd* pWnd = (CWnd*)pMap->LookupPermanent(hWndChild);
  2708.     ASSERT(pWnd == NULL || pWnd->m_hWnd == hWndChild);
  2709.     if (pWnd == NULL)
  2710.     {
  2711. #ifndef _AFX_NO_OCC_SUPPORT
  2712.         // check if the window is an OLE control
  2713.         CWnd* pWndParent = (CWnd*)pMap->LookupPermanent(::GetParent(hWndChild));
  2714.         if (pWndParent != NULL && pWndParent->m_pCtrlCont != NULL)
  2715.         {
  2716.             // If a matching control site exists, it's an OLE control
  2717.             COleControlSite* pSite = (COleControlSite*)pWndParent->
  2718.                 m_pCtrlCont->m_siteMap.GetValueAt(hWndChild);
  2719.             if (pSite != NULL)
  2720.             {
  2721.                 CWnd wndTemp(hWndChild);
  2722.                 wndTemp.m_pCtrlSite = pSite;
  2723.                 LRESULT lResult = wndTemp.SendChildNotifyLastMsg(pResult);
  2724.                 wndTemp.m_hWnd = NULL;
  2725.                 return lResult;
  2726.             }
  2727.         }
  2728. #endif //!_AFX_NO_OCC_SUPPORT
  2729.         return FALSE;
  2730.     }
  2731.  
  2732.     // only OLE controls and permanent windows will get reflected msgs
  2733.     ASSERT(pWnd != NULL);
  2734.     return pWnd->SendChildNotifyLastMsg(pResult);
  2735. }
  2736.  
  2737. BOOL CWnd::OnChildNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT* pResult)
  2738. {
  2739. #ifndef _AFX_NO_OCC_SUPPORT
  2740.     if (m_pCtrlSite != NULL)
  2741.     {
  2742.         // first forward raw OCM_ messages to OLE control sources
  2743.         LRESULT lResult = SendMessage(OCM__BASE+uMsg, wParam, lParam);
  2744.         if (uMsg >= WM_CTLCOLORMSGBOX && uMsg <= WM_CTLCOLORSTATIC &&
  2745.             (HBRUSH)lResult == NULL)
  2746.         {
  2747.             // for WM_CTLCOLOR msgs, returning NULL implies continue routing
  2748.             return FALSE;
  2749.         }
  2750.         if (pResult != NULL)
  2751.             *pResult = lResult;
  2752.         return TRUE;
  2753.     }
  2754. #endif
  2755.  
  2756.     return ReflectChildNotify(uMsg, wParam, lParam, pResult);
  2757. }
  2758.  
  2759. BOOL CWnd::ReflectChildNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT* pResult)
  2760. {
  2761.     // Note: reflected messages are send directly to CWnd::OnWndMsg
  2762.     //  and CWnd::OnCmdMsg for speed and because these messages are not
  2763.     //  routed by normal OnCmdMsg routing (they are only dispatched)
  2764.  
  2765.     switch (uMsg)
  2766.     {
  2767.     // normal messages (just wParam, lParam through OnWndMsg)
  2768.     case WM_HSCROLL:
  2769.     case WM_VSCROLL:
  2770.     case WM_PARENTNOTIFY:
  2771.     case WM_DRAWITEM:
  2772.     case WM_MEASUREITEM:
  2773.     case WM_DELETEITEM:
  2774.     case WM_VKEYTOITEM:
  2775.     case WM_CHARTOITEM:
  2776.     case WM_COMPAREITEM:
  2777.         // reflect the message through the message map as WM_REFLECT_BASE+uMsg
  2778.         return CWnd::OnWndMsg(WM_REFLECT_BASE+uMsg, wParam, lParam, pResult);
  2779.  
  2780.     // special case for WM_COMMAND
  2781.     case WM_COMMAND:
  2782.         {
  2783.             // reflect the message through the message map as OCM_COMMAND
  2784.             int nCode = HIWORD(wParam);
  2785.             if (CWnd::OnCmdMsg(0, MAKELONG(nCode, WM_REFLECT_BASE+WM_COMMAND), NULL, NULL))
  2786.             {
  2787.                 if (pResult != NULL)
  2788.                     *pResult = 1;
  2789.                 return TRUE;
  2790.             }
  2791.         }
  2792.         break;
  2793.  
  2794.     // special case for WM_NOTIFY
  2795.     case WM_NOTIFY:
  2796.         {
  2797.             // reflect the message through the message map as OCM_NOTIFY
  2798.             NMHDR* pNMHDR = (NMHDR*)lParam;
  2799.             int nCode = pNMHDR->code;
  2800.             AFX_NOTIFY notify;
  2801.             notify.pResult = pResult;
  2802.             notify.pNMHDR = pNMHDR;
  2803.             return CWnd::OnCmdMsg(0, MAKELONG(nCode, WM_REFLECT_BASE+WM_NOTIFY), ¬ify, NULL);
  2804.         }
  2805.  
  2806.     // other special cases (WM_CTLCOLOR family)
  2807.     default:
  2808.         if (uMsg >= WM_CTLCOLORMSGBOX && uMsg <= WM_CTLCOLORSTATIC)
  2809.         {
  2810.             // fill in special struct for compatiblity with 16-bit WM_CTLCOLOR
  2811.             AFX_CTLCOLOR ctl;
  2812.             ctl.hDC = (HDC)wParam;
  2813.             ctl.nCtlType = uMsg - WM_CTLCOLORMSGBOX;
  2814.             ASSERT(ctl.nCtlType >= CTLCOLOR_MSGBOX);
  2815.             ASSERT(ctl.nCtlType <= CTLCOLOR_STATIC);
  2816.  
  2817.             // reflect the message through the message map as OCM_CTLCOLOR
  2818.             BOOL bResult = CWnd::OnWndMsg(WM_REFLECT_BASE+WM_CTLCOLOR, 0, (LPARAM)&ctl, pResult);
  2819.             if ((HBRUSH)*pResult == NULL)
  2820.                 bResult = FALSE;
  2821.             return bResult;
  2822.         }
  2823.         break;
  2824.     }
  2825.  
  2826.     return FALSE;   // let the parent handle it
  2827. }
  2828.  
  2829. void CWnd::OnParentNotify(UINT message, LPARAM lParam)
  2830. {
  2831.     if ((LOWORD(message) == WM_CREATE || LOWORD(message) == WM_DESTROY))
  2832.     {
  2833.         if (ReflectLastMsg((HWND)lParam))
  2834.             return;     // eat it
  2835.     }
  2836.     // not handled - do default
  2837.     Default();
  2838. }
  2839.  
  2840. LRESULT CWnd::OnActivateTopLevel(WPARAM wParam, LPARAM)
  2841. {
  2842.     if (LOWORD(wParam) == WA_INACTIVE)
  2843.     {
  2844.         _AFX_THREAD_STATE* pThreadState = AfxGetThreadState();
  2845.         if (!(pThreadState->m_lastInfo.uFlags & TTF_ALWAYSTIP))
  2846.             CancelToolTips(TRUE);
  2847.     }
  2848.  
  2849.     return 0;
  2850. }
  2851.  
  2852. void CWnd::OnSysColorChange()
  2853. {
  2854.     CWinApp* pApp = AfxGetApp();
  2855.     _AFX_WIN_STATE* pWinState = _afxWinState;
  2856.     if (pApp->m_pMainWnd == this)
  2857.     {
  2858.         // recolor global brushes used by control bars
  2859.         afxData.UpdateSysColors();
  2860.  
  2861. #ifdef _MAC
  2862.         // redetermine the solid color to be used for the gray background brush
  2863.         if (pWinState->m_crDlgTextClr != (COLORREF)-1)
  2864.         {
  2865.             pApp->SetDialogBkColor(pWinState->m_crDlgBkClr,
  2866.                 pWinState->m_crDlgTextClr);
  2867.         }
  2868. #endif
  2869.     }
  2870.  
  2871. #ifndef _MAC
  2872.     if (!afxContextIsDLL)
  2873.     {
  2874.         if (AfxGetThread() != NULL && AfxGetThread()->m_pMainWnd == this)
  2875.         {
  2876.             _AFX_CTL3D_STATE* pCtl3dState = _afxCtl3dState;
  2877.             // allow CTL3D32.DLL to be notified of color change
  2878.             if (pCtl3dState->m_pfnColorChange != NULL)
  2879.                 (*pCtl3dState->m_pfnColorChange)();
  2880.         }
  2881.     }
  2882. #endif
  2883.  
  2884.     // forward this message to all other child windows
  2885.     if (!(GetStyle() & WS_CHILD))
  2886.         SendMessageToDescendants(WM_SYSCOLORCHANGE, 0, 0L, TRUE, TRUE);
  2887.  
  2888.     Default();
  2889. }
  2890.  
  2891. void CWnd::OnSettingChange(UINT uFlags, LPCTSTR lpszSection)
  2892. {
  2893.     UNUSED_ALWAYS(uFlags);
  2894.     UNUSED_ALWAYS(lpszSection);
  2895.  
  2896. #ifndef _MAC
  2897.     if (!afxContextIsDLL)
  2898.     {
  2899.         _AFX_CTL3D_STATE* pCtl3dState = _afxCtl3dState;
  2900.         // allow CTL3D32.DLL to update from WIN.INI settings
  2901.         if (AfxGetThread() != NULL && AfxGetThread()->m_pMainWnd == this &&
  2902.             pCtl3dState->m_pfnWinIniChange != NULL)
  2903.         {
  2904.             (*pCtl3dState->m_pfnWinIniChange)();
  2905.         }
  2906.     }
  2907.  
  2908.     // force refresh of settings that we cache
  2909.  
  2910.     _AfxGetMouseScrollLines(TRUE);
  2911. #endif
  2912.  
  2913.     CWnd::OnDisplayChange(0, 0);    // to update system metrics, etc.
  2914. }
  2915.  
  2916. void CWnd::OnWinIniChange(LPCTSTR lpszSection)
  2917. {
  2918.     UNUSED_ALWAYS(lpszSection);
  2919.  
  2920.     // this function is provided for backward compatibility only
  2921.     // it is called only in Windows NT 3.51; in Windows 95 and
  2922.     // Windows NT, OnSettingChange is called
  2923.  
  2924. #ifndef _MAC
  2925.     if (!afxContextIsDLL)
  2926.     {
  2927.         _AFX_CTL3D_STATE* pCtl3dState = _afxCtl3dState;
  2928.         // allow CTL3D32.DLL to update from WIN.INI settings
  2929.         if (AfxGetThread() != NULL && AfxGetThread()->m_pMainWnd == this &&
  2930.             pCtl3dState->m_pfnWinIniChange != NULL)
  2931.         {
  2932.             (*pCtl3dState->m_pfnWinIniChange)();
  2933.         }
  2934.     }
  2935. #endif
  2936.  
  2937.     CWnd::OnDisplayChange(0, 0);    // to update system metrics, etc.
  2938. }
  2939.  
  2940. void CWnd::OnDevModeChange(LPTSTR lpDeviceName)
  2941. {
  2942.     if (AfxGetThread() != NULL && AfxGetThread()->m_pMainWnd == this)
  2943.         AfxGetApp()->DevModeChange(lpDeviceName);
  2944.     // forward this message to all other child windows
  2945.     if (!(GetStyle() & WS_CHILD))
  2946.     {
  2947.         const MSG* pMsg = GetCurrentMessage();
  2948.         SendMessageToDescendants(pMsg->message, pMsg->wParam, pMsg->lParam,
  2949.             TRUE, TRUE);
  2950.     }
  2951. }
  2952.  
  2953. BOOL CWnd::OnHelpInfo(HELPINFO* /*pHelpInfo*/)
  2954. {
  2955.     if (!(GetStyle() & WS_CHILD))
  2956.     {
  2957.         CWnd* pMainWnd = AfxGetMainWnd();
  2958.         if (pMainWnd != NULL &&
  2959.             GetKeyState(VK_SHIFT) >= 0 &&
  2960.             GetKeyState(VK_CONTROL) >= 0 &&
  2961.             GetKeyState(VK_MENU) >= 0)
  2962.         {
  2963.             pMainWnd->SendMessage(WM_COMMAND, ID_HELP);
  2964.             return TRUE;
  2965.         }
  2966.     }
  2967.     return Default();
  2968. }
  2969.  
  2970. LRESULT CWnd::OnDisplayChange(WPARAM, LPARAM)
  2971. {
  2972.     // update metrics if this window is the main window
  2973.     CWinApp* pApp = AfxGetApp();
  2974.     if (pApp->m_pMainWnd == this)
  2975.     {
  2976.         // update any system metrics cache
  2977.         afxData.UpdateSysMetrics();
  2978.     }
  2979.  
  2980.     // forward this message to all other child windows
  2981.     if (!(GetStyle() & WS_CHILD))
  2982.     {
  2983.         const MSG* pMsg = GetCurrentMessage();
  2984.         SendMessageToDescendants(pMsg->message, pMsg->wParam, pMsg->lParam,
  2985.             TRUE, TRUE);
  2986.     }
  2987.  
  2988.     return Default();
  2989. }
  2990.  
  2991. #ifdef _MAC
  2992. LRESULT CWnd::OnMacintosh(WPARAM wParam, LPARAM lParam)
  2993. {
  2994.     GDEVICEINFO* pgdi = (GDEVICEINFO*) lParam;
  2995.  
  2996.     if (LOWORD(wParam) == WLM_DEVICECHANGED && pgdi->hwnd == m_hWnd)
  2997.     {
  2998.         const MSG* pMsg = GetCurrentMessage();
  2999.         SendMessageToDescendants(pMsg->message, pMsg->wParam, pMsg->lParam,
  3000.             TRUE, TRUE);
  3001.     }
  3002.  
  3003.     return Default();
  3004. }
  3005. #endif
  3006.  
  3007. LRESULT CWnd::OnDragList(WPARAM, LPARAM lParam)
  3008. {
  3009.     LPDRAGLISTINFO lpInfo = (LPDRAGLISTINFO)lParam;
  3010.     ASSERT(lpInfo != NULL);
  3011.  
  3012.     LRESULT lResult;
  3013.     if (ReflectLastMsg(lpInfo->hWnd, &lResult))
  3014.         return (int)lResult;    // eat it
  3015.  
  3016.     // not handled - do default
  3017.     return (int)Default();
  3018. }
  3019.  
  3020. void CWnd::OnHScroll(UINT, UINT, CScrollBar* pScrollBar)
  3021. {
  3022.     if (pScrollBar != NULL && pScrollBar->SendChildNotifyLastMsg())
  3023.         return;     // eat it
  3024.  
  3025.     Default();
  3026. }
  3027.  
  3028. void CWnd::OnVScroll(UINT, UINT, CScrollBar* pScrollBar)
  3029. {
  3030.     if (pScrollBar != NULL && pScrollBar->SendChildNotifyLastMsg())
  3031.         return;     // eat it
  3032.  
  3033.     Default();
  3034. }
  3035.  
  3036. void CWnd::OnEnterIdle(UINT /*nWhy*/, CWnd* /*pWho*/)
  3037. {
  3038.     // WINBUG: In some OLE inplace active scenarios, OLE will post a
  3039.     // message instead of sending it.  This causes so many WM_ENTERIDLE
  3040.     // messages to be sent that tasks running in the background stop
  3041.     // running.  By dispatching the pending WM_ENTERIDLE messages
  3042.     // when the first one is received, we trick Windows into thinking
  3043.     // that only one was really sent and dispatched.
  3044.     {
  3045.         MSG msg;
  3046.         while (PeekMessage(&msg, NULL, WM_ENTERIDLE, WM_ENTERIDLE, PM_REMOVE))
  3047.             DispatchMessage(&msg);
  3048.     }
  3049.  
  3050.     Default();
  3051. }
  3052.  
  3053. HBRUSH CWnd::OnCtlColor(CDC*, CWnd* pWnd, UINT)
  3054. {
  3055.     ASSERT(pWnd != NULL && pWnd->m_hWnd != NULL);
  3056.     LRESULT lResult;
  3057.     if (pWnd->SendChildNotifyLastMsg(&lResult))
  3058.         return (HBRUSH)lResult;     // eat it
  3059.     return (HBRUSH)Default();
  3060. }
  3061.  
  3062. // special helper for Gray OnCtlColor routines
  3063. HBRUSH CWnd::OnGrayCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
  3064. {
  3065.     LRESULT lResult;
  3066.     if (pWnd->SendChildNotifyLastMsg(&lResult))
  3067.         return (HBRUSH)lResult;     // eat it
  3068.  
  3069.     _AFX_WIN_STATE* pWinState = _afxWinState;
  3070.     if (!GrayCtlColor(pDC->m_hDC, pWnd->GetSafeHwnd(), nCtlColor,
  3071.       pWinState->m_hDlgBkBrush, pWinState->m_crDlgTextClr))
  3072.         return (HBRUSH)Default();
  3073.     return pWinState->m_hDlgBkBrush;
  3074. }
  3075.  
  3076. // implementation of OnCtlColor for default gray backgrounds
  3077. //   (works for any window containing controls)
  3078. //  return value of FALSE means caller must call DefWindowProc's default
  3079. //  TRUE means that 'hbrGray' will be used and the appropriate text
  3080. //    ('clrText') and background colors are set.
  3081. BOOL PASCAL CWnd::GrayCtlColor(HDC hDC, HWND hWnd, UINT nCtlColor,
  3082.     HBRUSH hbrGray, COLORREF clrText)
  3083. {
  3084.     if (hDC == NULL)
  3085.     {
  3086.         // sometimes Win32 passes a NULL hDC in the WM_CTLCOLOR message.
  3087.         TRACE0("Warning: hDC is NULL in CWnd::GrayCtlColor; WM_CTLCOLOR not processed.\n");
  3088.         return FALSE;
  3089.     }
  3090.  
  3091.     if (hbrGray == NULL ||
  3092.         nCtlColor == CTLCOLOR_EDIT || nCtlColor == CTLCOLOR_MSGBOX ||
  3093.         nCtlColor == CTLCOLOR_SCROLLBAR)
  3094.     {
  3095.         return FALSE;
  3096.     }
  3097.  
  3098.     if (nCtlColor == CTLCOLOR_LISTBOX)
  3099.     {
  3100.         // only handle requests to draw the space between edit and drop button
  3101.         //  in a drop-down combo (not a drop-down list)
  3102.         if (!_AfxIsComboBoxControl(hWnd, (UINT)CBS_DROPDOWN))
  3103.             return FALSE;
  3104.     }
  3105.  
  3106.     // set background color and return handle to brush
  3107.     LOGBRUSH logbrush;
  3108.     VERIFY(::GetObject(hbrGray, sizeof(LOGBRUSH), (LPVOID)&logbrush));
  3109.     ::SetBkColor(hDC, logbrush.lbColor);
  3110.     if (clrText == (COLORREF)-1)
  3111.         clrText = ::GetSysColor(COLOR_WINDOWTEXT);  // normal text
  3112.     ::SetTextColor(hDC, clrText);
  3113.     return TRUE;
  3114. }
  3115.  
  3116. LRESULT CWnd::OnQuery3dControls(WPARAM, LPARAM)
  3117. {
  3118.     // This is message handler is not in CWnd's message map.
  3119.     // It is placed in various derived classes' message maps to enable
  3120.     // 3D controls for specific window types only.
  3121.  
  3122.     return 0xFFFF;  // CTL3D_ALL
  3123. }
  3124.  
  3125. /////////////////////////////////////////////////////////////////////////////
  3126. // 'dialog data' support
  3127.  
  3128. BOOL CWnd::UpdateData(BOOL bSaveAndValidate)
  3129. {
  3130.     ASSERT(::IsWindow(m_hWnd)); // calling UpdateData before DoModal?
  3131.  
  3132.     CDataExchange dx(this, bSaveAndValidate);
  3133.  
  3134.     // prevent control notifications from being dispatched during UpdateData
  3135.     _AFX_THREAD_STATE* pThreadState = AfxGetThreadState();
  3136.     HWND hWndOldLockout = pThreadState->m_hLockoutNotifyWindow;
  3137.     ASSERT(hWndOldLockout != m_hWnd);   // must not recurse
  3138.     pThreadState->m_hLockoutNotifyWindow = m_hWnd;
  3139.  
  3140.     BOOL bOK = FALSE;       // assume failure
  3141.     TRY
  3142.     {
  3143.         DoDataExchange(&dx);
  3144.         bOK = TRUE;         // it worked
  3145.     }
  3146.     CATCH(CUserException, e)
  3147.     {
  3148.         // validation failed - user already alerted, fall through
  3149.         ASSERT(bOK == FALSE);
  3150.         // Note: DELETE_EXCEPTION_(e) not required
  3151.     }
  3152.     AND_CATCH_ALL(e)
  3153.     {
  3154.         // validation failed due to OOM or other resource failure
  3155.         e->ReportError(MB_ICONEXCLAMATION, AFX_IDP_INTERNAL_FAILURE);
  3156.         ASSERT(!bOK);
  3157.         DELETE_EXCEPTION(e);
  3158.     }
  3159.     END_CATCH_ALL
  3160.  
  3161.     pThreadState->m_hLockoutNotifyWindow = hWndOldLockout;
  3162.     return bOK;
  3163. }
  3164.  
  3165. CDataExchange::CDataExchange(CWnd* pDlgWnd, BOOL bSaveAndValidate)
  3166. {
  3167.     ASSERT_VALID(pDlgWnd);
  3168.     m_bSaveAndValidate = bSaveAndValidate;
  3169.     m_pDlgWnd = pDlgWnd;
  3170.     m_hWndLastControl = NULL;
  3171. }
  3172.  
  3173. /////////////////////////////////////////////////////////////////////////////
  3174. // Centering dialog support (works for any non-child window)
  3175.  
  3176. void CWnd::CenterWindow(CWnd* pAlternateOwner)
  3177. {
  3178.     ASSERT(::IsWindow(m_hWnd));
  3179.  
  3180.     // determine owner window to center against
  3181.     DWORD dwStyle = GetStyle();
  3182.     HWND hWndCenter = pAlternateOwner->GetSafeHwnd();
  3183.     if (pAlternateOwner == NULL)
  3184.     {
  3185.         if (dwStyle & WS_CHILD)
  3186.             hWndCenter = ::GetParent(m_hWnd);
  3187.         else
  3188.             hWndCenter = ::GetWindow(m_hWnd, GW_OWNER);
  3189.         if (hWndCenter != NULL)
  3190.         {
  3191.             // let parent determine alternate center window
  3192.             HWND hWndTemp =
  3193.                 (HWND)::SendMessage(hWndCenter, WM_QUERYCENTERWND, 0, 0);
  3194.             if (hWndTemp != NULL)
  3195.                 hWndCenter = hWndTemp;
  3196.         }
  3197.     }
  3198.  
  3199.     // get coordinates of the window relative to its parent
  3200.     CRect rcDlg;
  3201.     GetWindowRect(&rcDlg);
  3202.     CRect rcArea;
  3203.     CRect rcCenter;
  3204.     HWND hWndParent;
  3205.     if (!(dwStyle & WS_CHILD))
  3206.     {
  3207.         // don't center against invisible or minimized windows
  3208.         if (hWndCenter != NULL)
  3209.         {
  3210.             DWORD dwStyle = ::GetWindowLong(hWndCenter, GWL_STYLE);
  3211.             if (!(dwStyle & WS_VISIBLE) || (dwStyle & WS_MINIMIZE))
  3212.                 hWndCenter = NULL;
  3213.         }
  3214.         // center within screen coordinates
  3215.         SystemParametersInfo(SPI_GETWORKAREA, NULL, &rcArea, NULL);
  3216.  
  3217.         if (hWndCenter == NULL)
  3218.             rcCenter = rcArea;
  3219.         else
  3220.         {
  3221. #ifndef _MAC
  3222.             ::GetWindowRect(hWndCenter, &rcCenter);
  3223. #else
  3224.             ::GetClientRect(hWndCenter, &rcCenter);
  3225.             ::MapWindowPoints(hWndCenter, HWND_DESKTOP, (POINT*)&rcCenter, 2);
  3226. #endif
  3227.         }
  3228.     }
  3229.     else
  3230.     {
  3231.         // center within parent client coordinates
  3232.         hWndParent = ::GetParent(m_hWnd);
  3233.         ASSERT(::IsWindow(hWndParent));
  3234.  
  3235.         ::GetClientRect(hWndParent, &rcArea);
  3236.         ASSERT(::IsWindow(hWndCenter));
  3237.         ::GetClientRect(hWndCenter, &rcCenter);
  3238.         ::MapWindowPoints(hWndCenter, hWndParent, (POINT*)&rcCenter, 2);
  3239.     }
  3240.  
  3241. #ifndef _MAC
  3242.     // find dialog's upper left based on rcCenter
  3243.     int xLeft = (rcCenter.left + rcCenter.right) / 2 - rcDlg.Width() / 2;
  3244.     int yTop = (rcCenter.top + rcCenter.bottom) / 2 - rcDlg.Height() / 2;
  3245. #else
  3246.     // find dialog's upper left based on rcCenter
  3247.     // (Mac UI puts 1/5th of parent window above dialog instead of 1/2)
  3248.     int xLeft = (rcCenter.left + rcCenter.right) / 2 - rcDlg.Width() / 2;
  3249.     int yTop = (rcCenter.bottom - rcCenter.top) - rcDlg.Height();
  3250.     yTop = rcCenter.top + yTop / 5;
  3251. #endif
  3252.  
  3253.     // if the dialog is outside the screen, move it inside
  3254.     if (xLeft < rcArea.left)
  3255.         xLeft = rcArea.left;
  3256.     else if (xLeft + rcDlg.Width() > rcArea.right)
  3257.         xLeft = rcArea.right - rcDlg.Width();
  3258.  
  3259.     if (yTop < rcArea.top)
  3260.         yTop = rcArea.top;
  3261.     else if (yTop + rcDlg.Height() > rcArea.bottom)
  3262.         yTop = rcArea.bottom - rcDlg.Height();
  3263.  
  3264.     // map screen coordinates to child coordinates
  3265.     SetWindowPos(NULL, xLeft, yTop, -1, -1,
  3266.         SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
  3267. }
  3268.  
  3269. BOOL CWnd::CheckAutoCenter()
  3270. {
  3271.     return TRUE;
  3272. }
  3273.  
  3274. /////////////////////////////////////////////////////////////////////////////
  3275. // Dialog initialization support
  3276.  
  3277. #ifdef _MAC
  3278. #pragma intrinsic(memcpy)
  3279. #endif
  3280.  
  3281. BOOL CWnd::ExecuteDlgInit(LPCTSTR lpszResourceName)
  3282. {
  3283.     // find resource handle
  3284.     LPVOID lpResource = NULL;
  3285.     HGLOBAL hResource = NULL;
  3286.     if (lpszResourceName != NULL)
  3287.     {
  3288.         HINSTANCE hInst = AfxFindResourceHandle(lpszResourceName, RT_DLGINIT);
  3289.         HRSRC hDlgInit = ::FindResource(hInst, lpszResourceName, RT_DLGINIT);
  3290.         if (hDlgInit != NULL)
  3291.         {
  3292.             // load it
  3293.             hResource = LoadResource(hInst, hDlgInit);
  3294.             if (hResource == NULL)
  3295.                 return FALSE;
  3296.             // lock it
  3297.             lpResource = LockResource(hResource);
  3298.             ASSERT(lpResource != NULL);
  3299.         }
  3300.     }
  3301.  
  3302.     // execute it
  3303.     BOOL bResult = ExecuteDlgInit(lpResource);
  3304.  
  3305.     // cleanup
  3306.     if (lpResource != NULL && hResource != NULL)
  3307.     {
  3308.         UnlockResource(hResource);
  3309.         FreeResource(hResource);
  3310.     }
  3311.     return bResult;
  3312. }
  3313.  
  3314. BOOL CWnd::ExecuteDlgInit(LPVOID lpResource)
  3315. {
  3316.     BOOL bSuccess = TRUE;
  3317.     if (lpResource != NULL)
  3318.     {
  3319.         UNALIGNED WORD* lpnRes = (WORD*)lpResource;
  3320.         while (bSuccess && *lpnRes != 0)
  3321.         {
  3322. #ifndef _MAC
  3323.             WORD nIDC = *lpnRes++;
  3324.             WORD nMsg = *lpnRes++;
  3325.             DWORD dwLen = *((UNALIGNED DWORD*&)lpnRes)++;
  3326. #else
  3327.             // Unfortunately we can't count on these values being
  3328.             // word-aligned (and dwLen is word-swapped besides), so
  3329.             // we have to pull them out a byte at a time to avoid
  3330.             // address errors on 68000s.
  3331.             WORD nIDC;
  3332.             WORD nMsg;
  3333.             DWORD dwLen;
  3334.  
  3335.             memcpy(&nIDC, lpnRes++, sizeof(WORD));
  3336.             memcpy(&nMsg, lpnRes++, sizeof(WORD));
  3337.             memcpy((WORD*)&dwLen + 1, lpnRes++, sizeof(WORD));
  3338.             memcpy(&dwLen, lpnRes++, sizeof(WORD));
  3339. #endif
  3340.             // In Win32 the WM_ messages have changed.  They have
  3341.             // to be translated from the 32-bit values to 16-bit
  3342.             // values here.
  3343.  
  3344.             #define WIN16_LB_ADDSTRING  0x0401
  3345.             #define WIN16_CB_ADDSTRING  0x0403
  3346.  
  3347.             if (nMsg == WIN16_LB_ADDSTRING)
  3348.                 nMsg = LB_ADDSTRING;
  3349.             else if (nMsg == WIN16_CB_ADDSTRING)
  3350.                 nMsg = CB_ADDSTRING;
  3351.  
  3352.             // check for invalid/unknown message types
  3353. #ifdef _AFX_NO_OCC_SUPPORT
  3354.             ASSERT(nMsg == LB_ADDSTRING || nMsg == CB_ADDSTRING);
  3355. #else
  3356.             ASSERT(nMsg == LB_ADDSTRING || nMsg == CB_ADDSTRING ||
  3357.                 nMsg == WM_OCC_LOADFROMSTREAM ||
  3358.                 nMsg == WM_OCC_LOADFROMSTREAM_EX ||
  3359.                 nMsg == WM_OCC_LOADFROMSTORAGE ||
  3360.                 nMsg == WM_OCC_LOADFROMSTORAGE_EX ||
  3361.                 nMsg == WM_OCC_INITNEW);
  3362. #endif
  3363.  
  3364. #ifdef _MAC
  3365.             // It's relatively safe to do this inplace since we'll
  3366.             // be freeing the resource when we're done with it.
  3367.             if (nMsg == LB_ADDSTRING || nMsg == CB_ADDSTRING)
  3368.                 _swab((char*)lpnRes, (char*)lpnRes, dwLen & ~1);
  3369. #endif
  3370. #ifdef _DEBUG
  3371.             // For AddStrings, the count must exactly delimit the
  3372.             // string, including the NULL termination.  This check
  3373.             // will not catch all mal-formed ADDSTRINGs, but will
  3374.             // catch some.
  3375.             if (nMsg == LB_ADDSTRING || nMsg == CB_ADDSTRING)
  3376.                 ASSERT(*((LPBYTE)lpnRes + (UINT)dwLen - 1) == 0);
  3377. #endif
  3378.  
  3379. #ifndef _AFX_NO_OCC_SUPPORT
  3380.             if (nMsg == LB_ADDSTRING || nMsg == CB_ADDSTRING)
  3381. #endif // !_AFX_NO_OCC_SUPPORT
  3382.             {
  3383.                 // List/Combobox returns -1 for error
  3384.                 if (::SendDlgItemMessageA(m_hWnd, nIDC, nMsg, 0, (LONG)lpnRes) == -1)
  3385.                     bSuccess = FALSE;
  3386.             }
  3387.  
  3388.             // skip past data
  3389.             lpnRes = (WORD*)((LPBYTE)lpnRes + (UINT)dwLen);
  3390.         }
  3391.     }
  3392.  
  3393.     // send update message to all controls after all other siblings loaded
  3394.     if (bSuccess)
  3395.         SendMessageToDescendants(WM_INITIALUPDATE, 0, 0, FALSE, FALSE);
  3396.  
  3397.     return bSuccess;
  3398. }
  3399.  
  3400. void CWnd::UpdateDialogControls(CCmdTarget* pTarget, BOOL bDisableIfNoHndler)
  3401. {
  3402.     CCmdUI state;
  3403.     CWnd wndTemp;       // very temporary window just for CmdUI update
  3404.  
  3405.     // walk all the kids - assume the IDs are for buttons
  3406.     for (HWND hWndChild = ::GetTopWindow(m_hWnd); hWndChild != NULL;
  3407.             hWndChild = ::GetNextWindow(hWndChild, GW_HWNDNEXT))
  3408.     {
  3409.         // send to buttons
  3410.         wndTemp.m_hWnd = hWndChild; // quick and dirty attach
  3411.         state.m_nID = _AfxGetDlgCtrlID(hWndChild);
  3412.         state.m_pOther = &wndTemp;
  3413.  
  3414.         // check for reflect handlers in the child window
  3415.         CWnd* pWnd = CWnd::FromHandlePermanent(hWndChild);
  3416.         if (pWnd != NULL)
  3417.         {
  3418.             // call it directly to disable any routing
  3419.             if (pWnd->CWnd::OnCmdMsg(0, MAKELONG(-1,
  3420.                 WM_COMMAND+WM_REFLECT_BASE), &state, NULL))
  3421.                 continue;
  3422.         }
  3423.  
  3424.         // check for handlers in the parent window
  3425.         if (CWnd::OnCmdMsg(state.m_nID, CN_UPDATE_COMMAND_UI, &state, NULL))
  3426.             continue;
  3427.  
  3428.         // determine whether to disable when no handler exists
  3429.         BOOL bDisableTemp = bDisableIfNoHndler;
  3430.         if (bDisableTemp)
  3431.         {
  3432.             if ((wndTemp.SendMessage(WM_GETDLGCODE) & DLGC_BUTTON) == 0)
  3433.             {
  3434.                 // non-button controls don't get automagically disabled
  3435.                 bDisableTemp = FALSE;
  3436.             }
  3437.             else
  3438.             {
  3439.                 // only certain button controls get automagically disabled
  3440.                 UINT nStyle = (UINT)(wndTemp.GetStyle() & 0x0F);
  3441.                 if (nStyle == (UINT)BS_AUTOCHECKBOX ||
  3442.                     nStyle == (UINT)BS_AUTO3STATE ||
  3443.                     nStyle == (UINT)BS_GROUPBOX ||
  3444.                     nStyle == (UINT)BS_AUTORADIOBUTTON)
  3445.                 {
  3446.                     bDisableTemp = FALSE;
  3447.                 }
  3448.             }
  3449.         }
  3450.         // check for handlers in the target (owner)
  3451.         state.DoUpdate(pTarget, bDisableTemp);
  3452.     }
  3453.     wndTemp.m_hWnd = NULL;      // quick and dirty detach
  3454. }
  3455.  
  3456. BOOL CWnd::PreTranslateInput(LPMSG lpMsg)
  3457. {
  3458.     ASSERT(::IsWindow(m_hWnd));
  3459.  
  3460.     // don't translate non-input events
  3461.     if ((lpMsg->message < WM_KEYFIRST || lpMsg->message > WM_KEYLAST) &&
  3462.         (lpMsg->message < WM_MOUSEFIRST || lpMsg->message > WM_MOUSELAST))
  3463.         return FALSE;
  3464.  
  3465.     return IsDialogMessage(lpMsg);
  3466. }
  3467.  
  3468. int CWnd::RunModalLoop(DWORD dwFlags)
  3469. {
  3470.     ASSERT(::IsWindow(m_hWnd)); // window must be created
  3471.     ASSERT(!(m_nFlags & WF_MODALLOOP)); // window must not already be in modal state
  3472.  
  3473.     // for tracking the idle time state
  3474.     BOOL bIdle = TRUE;
  3475.     LONG lIdleCount = 0;
  3476.     BOOL bShowIdle = (dwFlags & MLF_SHOWONIDLE) && !(GetStyle() & WS_VISIBLE);
  3477.     HWND hWndParent = ::GetParent(m_hWnd);
  3478.     m_nFlags |= (WF_MODALLOOP|WF_CONTINUEMODAL);
  3479.     MSG* pMsg = &AfxGetThread()->m_msgCur;
  3480.  
  3481.     // acquire and dispatch messages until the modal state is done
  3482.     for (;;)
  3483.     {
  3484.         ASSERT(ContinueModal());
  3485.  
  3486. #ifdef _MAC
  3487.         // PeekMessage is particularly expensive because it calls the Event Manager,
  3488.         // so don't call it if we don't need to
  3489.         if (bShowIdle && !GetInputState())
  3490.         {
  3491.             ShowWindow(SW_SHOWNORMAL);
  3492.             UpdateWindow();
  3493.             bShowIdle = FALSE;
  3494.         }
  3495. #endif
  3496.  
  3497.         // phase1: check to see if we can do idle work
  3498.         while (bIdle &&
  3499.             !::PeekMessage(pMsg, NULL, NULL, NULL, PM_NOREMOVE))
  3500.         {
  3501.             ASSERT(ContinueModal());
  3502.  
  3503.             // show the dialog when the message queue goes idle
  3504.             if (bShowIdle)
  3505.             {
  3506.                 ShowWindow(SW_SHOWNORMAL);
  3507.                 UpdateWindow();
  3508.                 bShowIdle = FALSE;
  3509.             }
  3510.  
  3511.             // call OnIdle while in bIdle state
  3512.             if (!(dwFlags & MLF_NOIDLEMSG) && hWndParent != NULL && lIdleCount == 0)
  3513.             {
  3514.                 // send WM_ENTERIDLE to the parent
  3515.                 ::SendMessage(hWndParent, WM_ENTERIDLE, MSGF_DIALOGBOX, (LPARAM)m_hWnd);
  3516.             }
  3517.             if ((dwFlags & MLF_NOKICKIDLE) ||
  3518.                 !SendMessage(WM_KICKIDLE, MSGF_DIALOGBOX, lIdleCount++))
  3519.             {
  3520.                 // stop idle processing next time
  3521.                 bIdle = FALSE;
  3522.             }
  3523.         }
  3524.  
  3525.         // phase2: pump messages while available
  3526.         do
  3527.         {
  3528.             ASSERT(ContinueModal());
  3529.  
  3530.             // pump message, but quit on WM_QUIT
  3531.             if (!AfxGetThread()->PumpMessage())
  3532.             {
  3533.                 AfxPostQuitMessage(0);
  3534.                 return -1;
  3535.             }
  3536.  
  3537.             // show the window when certain special messages rec'd
  3538.             if (bShowIdle &&
  3539.                 (pMsg->message == 0x118 || pMsg->message == WM_SYSKEYDOWN))
  3540.             {
  3541.                 ShowWindow(SW_SHOWNORMAL);
  3542.                 UpdateWindow();
  3543.                 bShowIdle = FALSE;
  3544.             }
  3545.  
  3546.             if (!ContinueModal())
  3547.                 goto ExitModal;
  3548.  
  3549.             // reset "no idle" state after pumping "normal" message
  3550.             if (AfxGetThread()->IsIdleMessage(pMsg))
  3551.             {
  3552.                 bIdle = TRUE;
  3553.                 lIdleCount = 0;
  3554.             }
  3555.  
  3556.         } while (::PeekMessage(pMsg, NULL, NULL, NULL, PM_NOREMOVE));
  3557.     }
  3558.  
  3559. ExitModal:
  3560.     m_nFlags &= ~(WF_MODALLOOP|WF_CONTINUEMODAL);
  3561.     return m_nModalResult;
  3562. }
  3563.  
  3564. BOOL CWnd::ContinueModal()
  3565. {
  3566.     return m_nFlags & WF_CONTINUEMODAL;
  3567. }
  3568.  
  3569. void CWnd::EndModalLoop(int nResult)
  3570. {
  3571.     ASSERT(::IsWindow(m_hWnd));
  3572.  
  3573.     // this result will be returned from CWnd::RunModalLoop
  3574.     m_nModalResult = nResult;
  3575.  
  3576.     // make sure a message goes through to exit the modal loop
  3577.     if (m_nFlags & WF_CONTINUEMODAL)
  3578.     {
  3579.         m_nFlags &= ~WF_CONTINUEMODAL;
  3580.         PostMessage(WM_NULL);
  3581.     }
  3582. }
  3583.  
  3584. /////////////////////////////////////////////////////////////////////////////
  3585. // Standard init called by WinMain
  3586.  
  3587. static BOOL AFXAPI RegisterWithIcon(WNDCLASS* pWndCls,
  3588.     LPCTSTR lpszClassName, UINT nIDIcon)
  3589. {
  3590.     pWndCls->lpszClassName = lpszClassName;
  3591.     HINSTANCE hInst = AfxFindResourceHandle(
  3592.         MAKEINTRESOURCE(nIDIcon), RT_GROUP_ICON);
  3593.     if ((pWndCls->hIcon = ::LoadIcon(hInst, MAKEINTRESOURCE(nIDIcon))) == NULL)
  3594.     {
  3595.         // use default icon
  3596.         pWndCls->hIcon = ::LoadIcon(NULL, IDI_APPLICATION);
  3597.     }
  3598.     return AfxRegisterClass(pWndCls);
  3599. }
  3600.  
  3601. BOOL AFXAPI AfxEndDeferRegisterClass(short fClass)
  3602. {
  3603.     BOOL bResult = FALSE;
  3604.  
  3605.     // common initialization
  3606.     WNDCLASS wndcls;
  3607.     memset(&wndcls, 0, sizeof(WNDCLASS));   // start with NULL defaults
  3608.     wndcls.lpfnWndProc = DefWindowProc;
  3609.     wndcls.hInstance = AfxGetInstanceHandle();
  3610.     wndcls.hCursor = afxData.hcurArrow;
  3611.  
  3612.     AFX_MODULE_STATE* pModuleState = AfxGetModuleState();
  3613.     if (fClass & AFX_WND_REG)
  3614.     {
  3615.         // Child windows - no brush, no icon, safest default class styles
  3616.         wndcls.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
  3617.         wndcls.lpszClassName = _afxWnd;
  3618.         bResult =  AfxRegisterClass(&wndcls);
  3619.         if (bResult)
  3620.             pModuleState->m_fRegisteredClasses |= AFX_WND_REG;
  3621.     }
  3622.     else if (fClass & AFX_WNDOLECONTROL_REG)
  3623.     {
  3624.         // OLE Control windows - use parent DC for speed
  3625.         wndcls.style |= CS_PARENTDC | CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
  3626.         wndcls.lpszClassName = _afxWndOleControl;
  3627.         bResult =  AfxRegisterClass(&wndcls);
  3628.         if (bResult)
  3629.             pModuleState->m_fRegisteredClasses |= AFX_WNDOLECONTROL_REG;
  3630.     }
  3631.     else if (fClass & AFX_WNDCONTROLBAR_REG)
  3632.     {
  3633.         // Control bar windows
  3634.         wndcls.style = 0;   // control bars don't handle double click
  3635.         wndcls.lpszClassName = _afxWndControlBar;
  3636.         wndcls.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
  3637.         bResult =  AfxRegisterClass(&wndcls);
  3638.         if (bResult)
  3639.             pModuleState->m_fRegisteredClasses |= AFX_WNDCONTROLBAR_REG;
  3640.     }
  3641.     else if (fClass & AFX_WNDMDIFRAME_REG)
  3642.     {
  3643.         // MDI Frame window (also used for splitter window)
  3644.         wndcls.style = CS_DBLCLKS;
  3645.         wndcls.hbrBackground = NULL;
  3646.         bResult = RegisterWithIcon(&wndcls, _afxWndMDIFrame, AFX_IDI_STD_MDIFRAME);
  3647.         if (bResult)
  3648.             pModuleState->m_fRegisteredClasses |= AFX_WNDMDIFRAME_REG;
  3649.     }
  3650.     else if (fClass & AFX_WNDFRAMEORVIEW_REG)
  3651.     {
  3652.         // SDI Frame or MDI Child windows or views - normal colors
  3653.         wndcls.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
  3654.         wndcls.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
  3655.         bResult = RegisterWithIcon(&wndcls, _afxWndFrameOrView, AFX_IDI_STD_FRAME);
  3656.         if (bResult)
  3657.             pModuleState->m_fRegisteredClasses |= AFX_WNDFRAMEORVIEW_REG;
  3658.     }
  3659.     else if (fClass & AFX_WNDCOMMCTLS_REG)
  3660.     {
  3661.         InitCommonControls();
  3662.         bResult = TRUE;
  3663.         pModuleState->m_fRegisteredClasses |= AFX_WNDCOMMCTLS_REG;
  3664.     }
  3665.  
  3666.     return bResult;
  3667. }
  3668.  
  3669. /////////////////////////////////////////////////////////////////////////////
  3670. // CFrameWnd (here for library granularity)
  3671.  
  3672. BOOL CWnd::IsFrameWnd() const
  3673. {
  3674.     return FALSE;
  3675. }
  3676.  
  3677. BOOL CFrameWnd::IsFrameWnd() const
  3678. {
  3679.     return TRUE;
  3680. }
  3681.  
  3682. BOOL CFrameWnd::IsTracking() const
  3683. {
  3684.     return m_nIDTracking != 0 &&
  3685.         m_nIDTracking != AFX_IDS_HELPMODEMESSAGE &&
  3686.         m_nIDTracking != AFX_IDS_IDLEMESSAGE;
  3687. }
  3688.  
  3689. /////////////////////////////////////////////////////////////////////////////
  3690. // CTL3D support
  3691.  
  3692. // Use SubclassCtl3d to add CTL3D support to an already subclassed control
  3693. // Usually only necessary if the control does not have one of the standard
  3694. //  Windows class names.
  3695. BOOL CWnd::SubclassCtl3d(int nControlType)
  3696. {
  3697.     ASSERT(!afxContextIsDLL);   // Should only be called by apps
  3698.     UNUSED_ALWAYS(nControlType);    // unused in Mac build
  3699.  
  3700.     if (afxContextIsDLL)
  3701.         return FALSE;
  3702.  
  3703.     ASSERT(m_hWnd != NULL);
  3704.  
  3705. #ifndef _MAC
  3706.     _AFX_CTL3D_STATE* pCtl3dState = _afxCtl3dState;
  3707.     if (nControlType == -1)
  3708.     {
  3709.         if (pCtl3dState->m_pfnSubclassCtl != NULL)
  3710.             return (*pCtl3dState->m_pfnSubclassCtl)(m_hWnd);
  3711.     }
  3712.     else
  3713.     {
  3714.         if (pCtl3dState->m_pfnSubclassCtlEx != NULL)
  3715.             return (*pCtl3dState->m_pfnSubclassCtlEx)(m_hWnd, nControlType);
  3716.     }
  3717. #endif
  3718.     return FALSE;
  3719. }
  3720.  
  3721. // Use SubclassDlg3d to add CTL3D support to an entire window.
  3722. //  Any windows created on the window will be automatically subclassed.
  3723. BOOL CWnd::SubclassDlg3d(DWORD dwMask)
  3724. {
  3725.     ASSERT(!afxContextIsDLL);   // Should only be called by apps
  3726.     UNUSED_ALWAYS(dwMask);      // unused in Mac build
  3727.  
  3728.     if (afxContextIsDLL)
  3729.         return FALSE;
  3730.  
  3731.     ASSERT(m_hWnd != NULL);
  3732.  
  3733. #ifndef _MAC
  3734.     _AFX_CTL3D_STATE* pCtl3dState = _afxCtl3dState;
  3735.     if (pCtl3dState->m_pfnSubclassDlgEx != NULL)
  3736.         return pCtl3dState->m_pfnSubclassDlgEx(m_hWnd, dwMask);
  3737. #endif
  3738.     return FALSE;
  3739. }
  3740.  
  3741. //this function can't be inlined because of _afxShell
  3742. void CWnd::DragAcceptFiles(BOOL bAccept)
  3743. {
  3744.     ASSERT(::IsWindow(m_hWnd));
  3745.     AfxDllDragAcceptFiles(m_hWnd, bAccept);
  3746. }
  3747.  
  3748. /////////////////////////////////////////////////////////////////////////////
  3749. // Extra CWnd support for dynamic subclassing of controls
  3750.  
  3751. BOOL CWnd::SubclassWindow(HWND hWnd)
  3752. {
  3753.     if (!Attach(hWnd))
  3754.         return FALSE;
  3755.  
  3756.     // allow any other subclassing to occur
  3757.     PreSubclassWindow();
  3758.  
  3759.     // now hook into the AFX WndProc
  3760.     WNDPROC* lplpfn = GetSuperWndProcAddr();
  3761.     WNDPROC oldWndProc = (WNDPROC)::SetWindowLong(hWnd, GWL_WNDPROC,
  3762.         (DWORD)AfxGetAfxWndProc());
  3763.     ASSERT(oldWndProc != (WNDPROC)AfxGetAfxWndProc());
  3764.  
  3765.     if (*lplpfn == NULL)
  3766.         *lplpfn = oldWndProc;   // the first control of that type created
  3767. #ifdef _DEBUG
  3768.     else if (*lplpfn != oldWndProc)
  3769.     {
  3770.         TRACE0("Error: Trying to use SubclassWindow with incorrect CWnd\n");
  3771.         TRACE0("\tderived class.\n");
  3772.         TRACE3("\thWnd = $%04X (nIDC=$%04X) is not a %hs.\n", (UINT)hWnd,
  3773.             _AfxGetDlgCtrlID(hWnd), GetRuntimeClass()->m_lpszClassName);
  3774.         ASSERT(FALSE);
  3775.         // undo the subclassing if continuing after assert
  3776.         ::SetWindowLong(hWnd, GWL_WNDPROC, (DWORD)oldWndProc);
  3777.     }
  3778. #endif
  3779.  
  3780.     return TRUE;
  3781. }
  3782.  
  3783. BOOL CWnd::SubclassDlgItem(UINT nID, CWnd* pParent)
  3784. {
  3785.     ASSERT(pParent != NULL);
  3786.     ASSERT(::IsWindow(pParent->m_hWnd));
  3787.  
  3788.     // check for normal dialog control first
  3789.     HWND hWndControl = ::GetDlgItem(pParent->m_hWnd, nID);
  3790.     if (hWndControl != NULL)
  3791.         return SubclassWindow(hWndControl);
  3792.  
  3793. #ifndef _AFX_NO_OCC_SUPPORT
  3794.     if (pParent->m_pCtrlCont != NULL)
  3795.     {
  3796.         // normal dialog control not found
  3797.         COleControlSite* pSite = pParent->m_pCtrlCont->FindItem(nID);
  3798.         if (pSite != NULL)
  3799.         {
  3800.             ASSERT(pSite->m_hWnd != NULL);
  3801.             VERIFY(SubclassWindow(pSite->m_hWnd));
  3802.  
  3803. #ifndef _AFX_NO_OCC_SUPPORT
  3804.             // If the control has reparented itself (e.g., invisible control),
  3805.             // make sure that the CWnd gets properly wired to its control site.
  3806.             if (pParent->m_hWnd != ::GetParent(pSite->m_hWnd))
  3807.                 AttachControlSite(pParent);
  3808. #endif //!_AFX_NO_OCC_SUPPORT
  3809.  
  3810.             return TRUE;
  3811.         }
  3812.     }
  3813. #endif
  3814.  
  3815.     return FALSE;   // control not found
  3816. }
  3817.  
  3818. HWND CWnd::UnsubclassWindow()
  3819. {
  3820.     ASSERT(::IsWindow(m_hWnd));
  3821.  
  3822.     // set WNDPROC back to original value
  3823.     WNDPROC* lplpfn = GetSuperWndProcAddr();
  3824.     SetWindowLong(m_hWnd, GWL_WNDPROC, (LONG)*lplpfn);
  3825.     *lplpfn = NULL;
  3826.  
  3827.     // and Detach the HWND from the CWnd object
  3828.     return Detach();
  3829. }
  3830.  
  3831. ////////////////////////////////////////////////////////////////////////////
  3832. // out-of-line inlines for binary compatibility
  3833.  
  3834. #ifdef _AFXDLL
  3835. #ifndef _DEBUG
  3836.  
  3837. CPoint::CPoint(POINT initPt)
  3838.     { *(POINT*)this = initPt; }
  3839.  
  3840. #endif
  3841. #endif
  3842.  
  3843. #ifdef AFX_INIT_SEG
  3844. #pragma code_seg(AFX_INIT_SEG)
  3845. #endif
  3846.  
  3847. IMPLEMENT_DYNCREATE(CWnd, CCmdTarget)
  3848.  
  3849. /////////////////////////////////////////////////////////////////////////////
  3850.