home *** CD-ROM | disk | FTP | other *** search
/ Programming Languages Suite / ProgLangD.iso / C++-7 / DISK10 / MFC / SRC / WINDOW.CP$ / window
Encoding:
Text File  |  1992-03-18  |  37.3 KB  |  1,539 lines

  1. // This is a part of the Microsoft Foundation Classes C++ library.
  2. // Copyright (C) 1992 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 Microsoft
  7. // QuickHelp documentation provided with the library.
  8. // See these sources for detailed information regarding the
  9. // Microsoft Foundation Classes product.
  10.  
  11.  
  12. #include "afxwin.h"
  13. #pragma hdrstop
  14.  
  15. #include "winhand_.h"
  16. #include "window_.h"
  17.  
  18. #ifdef AFX_CORE_SEG
  19. #pragma code_seg(AFX_CORE_SEG)
  20. #endif
  21.  
  22. #ifdef _DEBUG
  23. #include "trace_.h"
  24. #undef THIS_FILE
  25. static char BASED_CODE THIS_FILE[] = __FILE__;
  26. #define new DEBUG_NEW
  27. #endif
  28.  
  29. /////////////////////////////////////////////////////////////////////////////
  30. // CHandleMap implementation
  31.  
  32. CObject*
  33. CHandleMap::FromHandle(HANDLE h)
  34. {
  35.     if (h == NULL)
  36.         return NULL;
  37.  
  38.     void* p;
  39.     if (LookupPermanent(h, p))
  40.         return (CObject*)p;     // return permanent one
  41.     else if (LookupTemporary(h, p))
  42.         return (CObject*)p;     // return last temporary one
  43.  
  44.     // This handle wasn't created by us, so we must create a temporary
  45.     // C++ object to wrap it.  We don't want the user to see this memory
  46.     // allocation, so we turn tracing off.
  47. #ifdef _DEBUG
  48.     BOOL bEnable = AfxEnableMemoryTracking(FALSE);
  49. #endif
  50.     CObject* pTemp = NewTempObject(h);
  51.     temporaryMap.SetAt((WORD)h, pTemp);
  52. #ifdef _DEBUG
  53.     AfxEnableMemoryTracking(bEnable);
  54. #endif
  55.     return pTemp;
  56. }
  57.  
  58. void
  59. CHandleMap::DeleteTemp()
  60. {
  61.     POSITION pos = temporaryMap.GetStartPosition();
  62.     while (pos != NULL)
  63.     {
  64.         WORD h; // not used 
  65.         void* p;
  66.         temporaryMap.GetNextAssoc(pos, h, p);
  67.         DeleteTempObject((CObject*)p);      // free it up
  68.     }
  69.  
  70.     temporaryMap.RemoveAll();       // free up dictionary links etc
  71. }
  72.  
  73. /////////////////////////////////////////////////////////////////////////////
  74. IMPLEMENT_DYNAMIC(CButton, CWnd)
  75. IMPLEMENT_DYNAMIC(CListBox, CWnd)
  76. IMPLEMENT_DYNAMIC(CComboBox, CWnd)
  77.  
  78. IMPLEMENT_DYNAMIC(CWnd, CObject)
  79.  
  80.  
  81. char NEAR _afxWnd[] = "AfxWnd";
  82. char NEAR _afxMDIFrameWnd[] = "AfxMDIFrameWnd";
  83. char NEAR _afxFrameWnd[] = "AfxFrameWnd";
  84.  
  85.  
  86. /////////////////////////////////////////////////////////////////////////////
  87. // Special bootstrap globals
  88.  
  89. static CWnd* pWndInit = NULL;
  90. static CDialog* pDlgInit = NULL;
  91.  
  92. /////////////////////////////////////////////////////////////////////////////
  93. // Official way to send message to a CWnd
  94.  
  95. struct CLastState
  96. {
  97.     MSG msg;
  98. };
  99. static CLastState NEAR lastState;
  100.     // global for last state of call to 'WindowProc'
  101.  
  102. LONG _AfxCallWndProc(CWnd* pWnd, HWND hWnd, UINT message,
  103.     UINT wParam, LONG lParam)
  104. {
  105.     LONG lResult;
  106.     CLastState oldState = lastState;    // save for nesting
  107.  
  108.     lastState.msg.hwnd = hWnd;
  109.     lastState.msg.message = message;
  110.     lastState.msg.wParam = wParam;
  111.     lastState.msg.lParam = lParam;
  112.  
  113. #ifdef _DEBUG
  114.     if (afxTraceFlags & 4)
  115.         AfxTraceMsg("WndProc", &lastState.msg);
  116. #endif
  117.  
  118.     // Catch exceptions thrown outside the scope of a callback
  119.     // in debug builds and warn the user.
  120.     TRY
  121.     {
  122.         lResult = pWnd->WindowProc(message, wParam, lParam);
  123.     }
  124.     CATCH (CException, e)
  125.     {
  126.         if (message == WM_CREATE)
  127.             lResult = -1;
  128.         else
  129.             lResult = 0;
  130.         TRACE("Warning: Uncaught exception in WindowProc (returning %ld)\n",
  131.             lResult);
  132.         ASSERT(FALSE);
  133.     }
  134.     END_CATCH
  135.  
  136.     lastState = oldState;
  137.     return lResult;
  138. }
  139.  
  140. const MSG* CWnd::GetCurrentMessage()
  141. {
  142.     // fill in time and position when asked for
  143.     lastState.msg.time = ::GetMessageTime();
  144.     *((DWORD*)&lastState.msg.pt) = ::GetMessagePos();
  145.     return &lastState.msg;
  146. }
  147.  
  148. LONG CWnd::Default()
  149.     // call DefWindowProc with the last message
  150. {
  151.     return DefWindowProc(lastState.msg.message,
  152.             lastState.msg.wParam, lastState.msg.lParam);
  153. }
  154.  
  155. /////////////////////////////////////////////////////////////////////////////
  156. // Map from HWND to CWnd*
  157.  
  158. class NEAR CWndHandleMap : public CHandleMap
  159. {
  160. public:
  161.     CObject* NewTempObject(HANDLE h)
  162.                 {
  163.                     // don't add in permanent
  164.                     CWnd* p = new CWnd();
  165.                     p->m_hWnd = (HWND)h;      // set after constructed
  166.                     return p;
  167.                 }
  168.     void DeleteTempObject(CObject* ob)
  169.                 {
  170.                     ASSERT(ob->IsKindOf(RUNTIME_CLASS(CWnd)));
  171.                     ((CWnd*)ob)->m_hWnd = NULL; // clear before destructed
  172.                     delete ob;
  173.                 }
  174.     CWndHandleMap()
  175.         { }
  176. };
  177. static CWndHandleMap NEAR hWndMap;
  178.  
  179. CWnd*
  180. CWnd::FromHandle(HWND hWnd)
  181. {
  182.     return (CWnd*)hWndMap.FromHandle(hWnd);
  183. }
  184.  
  185. CWnd*
  186. CWnd::FromHandlePermanent(HWND hWnd)
  187. {
  188.     // only look in the permanent map - does no allocations
  189.     void* p;
  190.     return (hWndMap.LookupPermanent(hWnd, p)) ? (CWnd*)p : NULL;
  191. }
  192.  
  193. void
  194. CWnd::DeleteTempMap()
  195. {
  196.     hWndMap.DeleteTemp();
  197. }
  198.  
  199. BOOL
  200. CWnd::Attach(HWND hWnd)
  201. {
  202.     ASSERT(m_hWnd == NULL);     // only attach once, detach on destroy
  203.     if (hWnd == NULL)
  204.         return FALSE;
  205.     hWndMap.SetPermanent(m_hWnd = hWnd, this);
  206.     return TRUE;
  207. }
  208.  
  209. HWND
  210. CWnd::Detach()
  211. {
  212.     HWND hWnd;
  213.     if ((hWnd = m_hWnd) != NULL)
  214.         hWndMap.RemovePermanent(m_hWnd);
  215.     m_hWnd = NULL;
  216.     return hWnd;
  217. }
  218.  
  219.  
  220. /////////////////////////////////////////////////////////////////////////////
  221. // One main WndProc for all CWnd's and derived classes
  222.  
  223. LONG FAR PASCAL AFX_EXPORT
  224. AfxWndProc(HWND hWnd, UINT message, UINT wParam, LONG lParam)
  225. {
  226.     register CWnd* pWnd;
  227.  
  228.     pWnd = CWnd::FromHandlePermanent(hWnd);
  229.     ASSERT(pWnd != NULL);
  230.     ASSERT(pWnd->m_hWnd == hWnd);
  231.  
  232.     LONG lResult = _AfxCallWndProc(pWnd, hWnd, message, wParam, lParam);
  233.  
  234.     return lResult;
  235. }
  236.  
  237. // Special case for remaining dialog cases
  238. // Most messages will go through the window proc (AfxWndProc) of the
  239. //   subclassed dialog.  Some messages like WM_SETFONT and WM_INITDIALOG
  240. //   are sent directly to the dialog proc only.  These messages cannot be
  241. //   passed on to DefWindowProc() or infinite recursion will result!
  242. // In responding to these messages, you shouldn't call the Default handler
  243. LONG FAR PASCAL AFX_EXPORT
  244. _AfxDlgProc(HWND hWnd, register UINT message, UINT wParam, LONG lParam)
  245. {
  246.     register CDialog* pDlg;
  247.  
  248.     // test for special case (Win 3.0 will call dialog proc instead
  249.     //  of SendMessage for these two messages).
  250.     if (message != WM_SETFONT && message != WM_INITDIALOG)
  251.         return 0L;      // normal handler
  252.  
  253.     // assume it is already wired up to a permanent one
  254.     pDlg = (CDialog*) CWnd::FromHandlePermanent(hWnd);
  255.     ASSERT(pDlg != NULL);
  256.     ASSERT(pDlg->m_hWnd == hWnd);
  257.  
  258.     // prepare for callback, make it look like message map call
  259.     LONG lResult = 0;
  260.     CLastState oldState = lastState;    // save for nesting
  261.  
  262.     lastState.msg.hwnd = hWnd;
  263.     lastState.msg.message = message;
  264.     lastState.msg.wParam = wParam;
  265.     lastState.msg.lParam = lParam;
  266.  
  267.     TRY
  268.     {
  269.         if (message == WM_SETFONT)
  270.             pDlg->OnSetFont(CFont::FromHandle((HFONT)wParam));
  271.         else // WM_INITDIALOG
  272.             lResult = pDlg->OnInitDialog();
  273.     }
  274.     CATCH (CException, e)
  275.     {
  276.         // fall through
  277.         TRACE("Warning: something went wrong in dialog init\n");
  278.         pDlg->EndDialog(IDCANCEL);  // something went wrong
  279.         ASSERT(FALSE);
  280.     }
  281.     END_CATCH
  282.  
  283.     lastState = oldState;
  284.     return lResult;
  285. }
  286.  
  287. /////////////////////////////////////////////////////////////////////////////
  288. // Window creation hook
  289. #ifdef STRICT
  290. static HHOOK pfnOldSendMsgHook = NULL;
  291. #else
  292. static HOOKPROC pfnOldSendMsgHook = NULL;
  293. #endif
  294.  
  295. #pragma optimize("q", off)    // disable pcode opt (Win 3.0 compatibility)
  296.  
  297. void FAR PASCAL AFX_EXPORT
  298. _AfxSendMsgHook(int code, UINT wParam, LONG lParam)
  299. {
  300.     struct HOOKINFO     // Hook info struct passed by send message hook
  301.     {
  302.         LONG lParam;
  303.         UINT wParam;
  304.         UINT msg;
  305.         HWND hWnd;
  306.     };
  307.     HOOKINFO FAR* hookInfo;
  308.  
  309.     if (code < 0)
  310.     {
  311.         ::DefHookProc(code, wParam, lParam, &pfnOldSendMsgHook);
  312.         return;
  313.     }
  314.  
  315.     ASSERT(pWndInit != NULL);
  316.     hookInfo = (HOOKINFO FAR*)lParam;
  317.     HWND hWnd = hookInfo->hWnd;
  318.  
  319.     // ignore non-creation messages
  320.     if (hookInfo->msg != WM_GETMINMAXINFO &&
  321.       hookInfo->msg != WM_NCCREATE)
  322.     {
  323.         // not being constructed
  324.         return;
  325.     }
  326.  
  327.     // Connect the HWND to pWndInit...
  328.     pWndInit->Attach(hWnd);
  329.  
  330.     // Subclass the window by replacing its window proc addr...
  331.     WNDPROC oldWndProc = (WNDPROC)::SetWindowLong(hWnd, GWL_WNDPROC,
  332.         (DWORD)AfxWndProc);
  333.     if (oldWndProc != (WNDPROC)AfxWndProc)
  334.     {
  335.         *(pWndInit->GetSuperWndProcAddr()) = oldWndProc; // save if not default
  336.     }
  337.  
  338.     // Unhook the send message hook since we don't need it any more
  339.     ::UnhookWindowsHook(WH_CALLWNDPROC, (HOOKPROC)_AfxSendMsgHook);
  340.     pWndInit = NULL;
  341. }
  342.  
  343. #pragma optimize("", on)    // return to default optimizations
  344.  
  345. void _AfxHookWindowCreate(register CWnd* pWnd)
  346. {
  347. #ifndef _WINDLL
  348.     if (_afxSetWindowsHookExProc == NULL)
  349.     {
  350.         pfnOldSendMsgHook = ::SetWindowsHook(WH_CALLWNDPROC,
  351.             (HOOKPROC)_AfxSendMsgHook);
  352.     }
  353.     else
  354.     {
  355. #ifdef STRICT
  356.         pfnOldSendMsgHook = (HHOOK)(*_afxSetWindowsHookExProc)(
  357.             WH_CALLWNDPROC, (HOOKPROC)_AfxSendMsgHook, AfxGetInstanceHandle(),
  358.             GetCurrentTask());
  359. #else
  360.         pfnOldSendMsgHook = (HOOKPROC)(*_afxSetWindowsHookExProc)(
  361.             WH_CALLWNDPROC, (HOOKPROC)_AfxSendMsgHook, AfxGetInstanceHandle(),
  362.             GetCurrentTask());
  363. #endif
  364.     }
  365. #else // _WINDLL
  366.     pfnOldSendMsgHook = ::SetWindowsHook(WH_CALLWNDPROC,
  367.         (HOOKPROC)_AfxSendMsgHook);
  368. #endif // _WINDLL
  369.  
  370.     ASSERT(pWnd != NULL);
  371.     ASSERT(pWnd->m_hWnd == NULL);   // only do once
  372.  
  373.     ASSERT(pWndInit == NULL);       // hook not already in progress
  374.     pWndInit = pWnd;
  375. }
  376.  
  377. BOOL _AfxUnhookWindowCreate()
  378.     // return TRUE if already unhooked
  379. {
  380.     if (pWndInit == NULL)
  381.         return TRUE;        // already unhooked => window create success
  382.     ::UnhookWindowsHook(WH_CALLWNDPROC, (HOOKPROC)_AfxSendMsgHook);
  383.     pWndInit = NULL;
  384.     return FALSE;
  385. }
  386.  
  387. /////////////////////////////////////////////////////////////////////////////
  388. // CWnd creation
  389.  
  390. BOOL CWnd::CreateEx(DWORD dwExStyle, LPCSTR lpClassName,
  391.         LPCSTR lpWindowName, DWORD dwStyle,
  392.         int x, int y, int nWidth, int nHeight,
  393.         HWND hWndParent, HMENU nIDorHMenu)
  394. {
  395.     _AfxHookWindowCreate(this);
  396.     HWND hWnd = ::CreateWindowEx(dwExStyle, lpClassName,
  397.             lpWindowName, dwStyle, x, y, nWidth, nHeight,
  398.             hWndParent, nIDorHMenu, AfxGetInstanceHandle(), NULL);
  399.  
  400.     _AfxUnhookWindowCreate();
  401.     if (hWnd == NULL)
  402.         return NULL;
  403.     ASSERT(hWnd == m_hWnd); // should have been set in send msg hook
  404.     return TRUE;
  405. }
  406.  
  407. // for child windows
  408. BOOL CWnd::Create(LPCSTR lpClassName,
  409.     LPCSTR lpWindowName, DWORD dwStyle,
  410.     const RECT& rect,
  411.     const CWnd* pParentWnd, UINT nID)
  412. {
  413.     ASSERT(pParentWnd != NULL);
  414.  
  415.     if (lpClassName == NULL)
  416.         lpClassName = _afxWnd;
  417.  
  418.     return CreateEx(0, lpClassName, lpWindowName,
  419.         dwStyle | WS_CHILD,
  420.         rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
  421.         pParentWnd->GetSafeHwnd(), (HMENU)nID);
  422. }
  423.  
  424. CWnd::~CWnd()
  425. {
  426.     DestroyWindow();
  427. }
  428.  
  429.  
  430. void CWnd::OnDestroy()
  431. {
  432. #ifndef _WINDLL
  433.     // Automatically quit when the main window is destroyed.
  434.     if (AfxGetApp()->m_pMainWnd == this)
  435.         ::PostQuitMessage(0);
  436. #endif // _WINDLL
  437.     Default();
  438. }
  439.  
  440. void CWnd::OnNcDestroy()
  441. {
  442.     // WM_NCDESTROY is the absolute LAST message sent.
  443.     if (AfxGetApp()->m_pMainWnd == this)
  444.         AfxGetApp()->m_pMainWnd = NULL;
  445.  
  446.     Default();
  447.     Detach();
  448.     ASSERT(m_hWnd == NULL);
  449.  
  450.     // call special post-cleanup routine
  451.     PostNcDestroy();
  452. }
  453.  
  454. void CWnd::PostNcDestroy()
  455. {
  456.     // default to nothing
  457. }
  458.  
  459. #ifdef _DEBUG
  460. void CWnd::AssertValid() const
  461. {
  462.     ASSERT(m_hWnd == NULL ||
  463.         (m_hWnd == (HWND)1 && this == &CWnd::wndBottom) ||
  464.         ::IsWindow(m_hWnd));
  465.     void* p;
  466.     ASSERT(m_hWnd == NULL ||
  467.         (m_hWnd == (HWND)1 && this == &CWnd::wndBottom) ||
  468.         hWndMap.LookupPermanent(m_hWnd, p) ||
  469.         hWndMap.LookupTemporary(m_hWnd, p));
  470. }
  471.  
  472. void CWnd::Dump(CDumpContext& dc) const
  473. {
  474.     CObject::Dump(dc);
  475.  
  476.     dc << "with window information:\n";
  477.     dc << "m_hWnd = " << (void NEAR*)m_hWnd;
  478.  
  479.     if ((UINT)m_hWnd > 1)
  480.     {
  481.         char szBuf [64];
  482.  
  483.         GetWindowText(szBuf, sizeof (szBuf));
  484.         dc << "\ncaption = \"" << szBuf << "\"";
  485.  
  486.         ::GetClassName(m_hWnd, szBuf, sizeof (szBuf));
  487.         dc << "\nclass name = \"" << szBuf << "\"";
  488.  
  489.         CRect rect;
  490.         GetWindowRect(&rect);
  491.         dc << "\nrect = " << rect;
  492.  
  493.         dc << "\nparent CWnd* = " << (void*)GetParent();
  494.  
  495.         dc << "\nstyle = " << (void FAR*)::GetWindowLong(m_hWnd, GWL_STYLE);
  496.         if (::GetWindowLong(m_hWnd, GWL_STYLE) & WS_CHILD)
  497.             dc << "\nid = " << ::GetWindowWord(m_hWnd, GWW_ID);
  498.     }
  499. }
  500. #endif
  501.  
  502. BOOL
  503. CWnd::DestroyWindow()
  504. {
  505.     if (m_hWnd == NULL)
  506.         return FALSE;
  507.  
  508.     void* p;
  509.     BOOL bInPermanentMap = hWndMap.LookupPermanent(m_hWnd, p);
  510.     BOOL bRet = ::DestroyWindow(m_hWnd);
  511.     // Note that 'this' may have been deleted at this point.
  512.     if (bInPermanentMap)
  513.     {
  514.         // Should have been detached by OnNcDestroy
  515.         ASSERT(!hWndMap.LookupPermanent(m_hWnd, p));
  516.     }
  517.     else
  518.     {
  519.         // Detach after DestroyWindow called just in case
  520.         Detach();
  521.     }
  522.     return bRet;
  523. }
  524.  
  525. /////////////////////////////////////////////////////////////////////////////
  526. // Default CWnd implementation
  527.  
  528. LONG CWnd::DefWindowProc(UINT nMsg, UINT wParam, LONG lParam)
  529. {
  530.     WNDPROC pfnWndProc;
  531.  
  532.     if ((pfnWndProc = *GetSuperWndProcAddr()) == NULL)
  533.         return ::DefWindowProc(m_hWnd, nMsg, wParam, lParam);
  534.     else
  535. #ifdef STRICT
  536.         return ::CallWindowProc(pfnWndProc, m_hWnd, nMsg, wParam, lParam);
  537. #else
  538.         return ::CallWindowProc((FARPROC)pfnWndProc, m_hWnd, nMsg, wParam, lParam);
  539. #endif
  540. }
  541.  
  542. WNDPROC* CWnd::GetSuperWndProcAddr()
  543. {
  544.     static WNDPROC pfnSuper = NULL;
  545.     ASSERT(pfnSuper == NULL);       // should never be changed !!!
  546.                     // if this is non-NULL, then a derived class of CWnd
  547.                     //  forgot to override 'superWndProc' as well as 'className'
  548.     return &pfnSuper;
  549. }
  550.  
  551. BOOL CWnd::PreTranslateMessage(MSG*)
  552. {
  553.     // no default processing
  554.     return FALSE;
  555. }
  556.  
  557. /////////////////////////////////////////////////////////////////////////////
  558. // CWnd will delegate owner draw messages to self drawing controls
  559.  
  560. // Drawing: for all 4 control types
  561. void CWnd::OnDrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
  562. {
  563.     UINT nType;
  564.     if ((nType = lpDrawItemStruct->CtlType) == ODT_MENU)
  565.     {
  566.         CMenu* pMenu = CMenu::FromHandle((HMENU)lpDrawItemStruct->hwndItem);
  567.         if (pMenu != NULL)
  568.         {
  569.             pMenu->DrawItem(lpDrawItemStruct);
  570.             return;
  571.         }
  572.     }
  573.     else
  574.     {
  575.         CWnd* pChild = CWnd::FromHandlePermanent(lpDrawItemStruct->hwndItem);
  576.         if (pChild != NULL)
  577.         {
  578.             if (nType == ODT_BUTTON &&
  579.                 pChild->IsKindOf(RUNTIME_CLASS(CButton)))
  580.             {
  581.                 ((CButton*)pChild)->DrawItem(lpDrawItemStruct);
  582.                 return;
  583.             }
  584.             else if (nType == ODT_LISTBOX &&
  585.                 pChild->IsKindOf(RUNTIME_CLASS(CListBox)))
  586.             {
  587.                 ((CListBox*)pChild)->DrawItem(lpDrawItemStruct);
  588.                 return;
  589.             }
  590.             else if (nType == ODT_COMBOBOX &&
  591.                 pChild->IsKindOf(RUNTIME_CLASS(CComboBox)))
  592.             {
  593.                 ((CComboBox*)pChild)->DrawItem(lpDrawItemStruct);
  594.                 return;
  595.             }
  596.         }
  597.     }
  598.     // not handled - do default
  599.     Default();
  600. }
  601.  
  602. // Drawing: for all 4 control types
  603. int CWnd::OnCompareItem(LPCOMPAREITEMSTRUCT lpCompareItemStruct)
  604. {
  605.     CWnd* pChild = CWnd::FromHandlePermanent(lpCompareItemStruct->hwndItem);
  606.     if (pChild != NULL)
  607.     {
  608.         UINT nType = lpCompareItemStruct->CtlType;
  609.         if (nType == ODT_LISTBOX &&
  610.             pChild->IsKindOf(RUNTIME_CLASS(CListBox)))
  611.         {
  612.             return ((CListBox*)pChild)->CompareItem(lpCompareItemStruct);
  613.         }
  614.         else if (nType == ODT_COMBOBOX &&
  615.             pChild->IsKindOf(RUNTIME_CLASS(CComboBox)))
  616.         {
  617.             return ((CComboBox*)pChild)->CompareItem(lpCompareItemStruct);
  618.         }
  619.     }
  620.     // not handled - do default
  621.     return (int)Default();
  622. }
  623.  
  624. void CWnd::OnDeleteItem(LPDELETEITEMSTRUCT lpDeleteItemStruct)
  625. {
  626.     CWnd* pChild = CWnd::FromHandlePermanent(lpDeleteItemStruct->hwndItem);
  627.     if (pChild != NULL)
  628.     {
  629.         UINT nType = lpDeleteItemStruct->CtlType;
  630.         if (nType == ODT_LISTBOX &&
  631.             pChild->IsKindOf(RUNTIME_CLASS(CListBox)))
  632.         {
  633.             ((CListBox*)pChild)->DeleteItem(lpDeleteItemStruct);
  634.             return;
  635.         }
  636.         else if (nType == ODT_COMBOBOX &&
  637.             pChild->IsKindOf(RUNTIME_CLASS(CComboBox)))
  638.         {
  639.             ((CComboBox*)pChild)->DeleteItem(lpDeleteItemStruct);
  640.             return;
  641.         }
  642.     }
  643.     // not handled - do default
  644.     Default();
  645. }
  646.  
  647.  
  648. static CMenu* FindPopupMenuFromID(CMenu* pMenu, UINT nID)
  649. {
  650.     // walk through all items, looking for ID match
  651.     UINT nItems = pMenu->GetMenuItemCount();
  652.     for (int iItem = 0; iItem < (int)nItems; iItem++)
  653.     {
  654.         if (pMenu->GetMenuState(iItem, MF_BYPOSITION) & MF_POPUP)
  655.         {
  656.             // recurse to child popup
  657.             CMenu* pPopup = FindPopupMenuFromID(pMenu->GetSubMenu(iItem), nID);
  658.             // try recursing
  659.             if (pPopup != NULL)
  660.                 return pPopup;
  661.         }
  662.         else if (pMenu->GetMenuItemID(iItem) == nID)
  663.         {
  664.             // it is a normal item inside our popup
  665.             return pMenu;
  666.         }
  667.     }
  668.     // not found
  669.     return NULL;
  670. }
  671.  
  672. // Measure item implementation relies on unique control/menu IDs
  673. void CWnd::OnMeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct)
  674. {
  675.     UINT nType;
  676.     if ((nType = lpMeasureItemStruct->CtlType) == ODT_MENU)
  677.     {
  678.         ASSERT(lpMeasureItemStruct->CtlID == 0);
  679.         CMenu* pMenu = FindPopupMenuFromID(GetMenu(),
  680.             lpMeasureItemStruct->itemID);
  681.         if (pMenu != NULL)
  682.         {
  683.             pMenu->MeasureItem(lpMeasureItemStruct);
  684.             return;
  685.         }
  686.         else
  687.         {
  688.             TRACE("Warning: unknown WM_MEASUREITEM request for"
  689.                 " menu item 0x%04X\n", lpMeasureItemStruct->itemID);
  690.         }
  691.     }
  692.     else
  693.     {
  694.         HWND hWndChild = ::GetDlgItem(m_hWnd, lpMeasureItemStruct->CtlID);
  695.         CWnd* pChild;
  696.         if (hWndChild != NULL &&
  697.             (pChild = CWnd::FromHandlePermanent(hWndChild)) != NULL)
  698.         {
  699.             if (nType == ODT_LISTBOX &&
  700.                 pChild->IsKindOf(RUNTIME_CLASS(CListBox)))
  701.             {
  702.                 ((CListBox*)pChild)->MeasureItem(lpMeasureItemStruct);
  703.                 return;
  704.             }
  705.             else if (nType == ODT_COMBOBOX &&
  706.                 pChild->IsKindOf(RUNTIME_CLASS(CComboBox)))
  707.             {
  708.                 ((CComboBox*)pChild)->MeasureItem(lpMeasureItemStruct);
  709.                 return;
  710.             }
  711.         }
  712.     }
  713.     // not handled - do default
  714.     Default();
  715. }
  716.  
  717. /////////////////////////////////////////////////////////////////////////////
  718. // CFrameWnd
  719.  
  720. IMPLEMENT_DYNAMIC(CFrameWnd, CWnd)
  721.  
  722. CFrameWnd::CFrameWnd()
  723. {
  724.     ASSERT(m_hWnd == NULL);
  725.     m_hAccelTable = NULL;
  726. }
  727.  
  728. CFrameWnd::~CFrameWnd()
  729. {
  730.     if (m_hAccelTable != NULL)
  731.         ::FreeResource(m_hAccelTable);
  732. }
  733.  
  734. void CFrameWnd::PostNcDestroy()
  735. {
  736.     // default for frame windows is to allocate them on the heap
  737.     //  the default post-cleanup is to 'delete this'.
  738.     // never explicitly call 'delete' on a CFrameWnd, use DestroyWindow instead
  739.     delete this;
  740. }
  741.  
  742. #ifdef _DEBUG
  743. void CFrameWnd::AssertValid() const
  744. {
  745.     CWnd::AssertValid();
  746. }
  747.  
  748. void CFrameWnd::Dump(CDumpContext& dc) const
  749. {
  750.     CWnd::Dump(dc);
  751.     dc << "\nm_hAccelTable = " << (UINT) m_hAccelTable;
  752. }
  753. #endif
  754.  
  755. BOOL CFrameWnd::LoadAccelTable(LPCSTR lpAccelTableName)
  756. {
  757.     ASSERT(m_hAccelTable == NULL);  // only do once
  758.     ASSERT(lpAccelTableName != NULL);
  759.  
  760.     m_hAccelTable = ::LoadAccelerators(AfxGetResourceHandle(),
  761.         lpAccelTableName);
  762.     return (m_hAccelTable != NULL);
  763. }
  764.  
  765. /////////////////////////////////////////////////////////////////////////////
  766. // Creation and window tree access
  767.  
  768. BOOL CFrameWnd::Create(LPCSTR lpClassName,
  769.     LPCSTR lpWindowName,
  770.     DWORD dwStyle, const RECT& rect,
  771.     const CWnd* pParentWnd,
  772.     LPCSTR lpMenuName)
  773. {
  774.     HMENU   hMenu = NULL;
  775.  
  776.     if (lpClassName == NULL)
  777.         lpClassName = _afxFrameWnd;
  778.  
  779.     if (lpMenuName != NULL)
  780.     {
  781.         // load in a menu that will get destroyed when window gets destroyed
  782.         hMenu = ::LoadMenu(AfxGetResourceHandle(), lpMenuName);
  783.         if (hMenu == NULL)
  784.         {
  785.             TRACE("Warning: failed to load menu for CFrameWnd\n");
  786.             return FALSE;
  787.         }
  788.     }
  789.  
  790.     if (!CreateEx(0L, lpClassName, lpWindowName, dwStyle,
  791.         rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
  792.         pParentWnd->GetSafeHwnd(), hMenu))
  793.     {
  794.         TRACE("Warning: failed to create CFrameWnd\n");
  795.         return FALSE;
  796.     }
  797.     return TRUE;
  798. }
  799.  
  800. CFrameWnd* CFrameWnd::GetChildFrame()
  801. {
  802.     return this;
  803. }
  804.  
  805. CFrameWnd* CFrameWnd::GetParentFrame()
  806. {
  807.     return this;
  808. }
  809.  
  810. BOOL CFrameWnd::PreTranslateMessage(MSG* pMsg)
  811. {
  812.     return (m_hAccelTable != NULL &&
  813.       ::TranslateAccelerator(m_hWnd, m_hAccelTable, pMsg));
  814. }
  815.  
  816.  
  817. /////////////////////////////////////////////////////////////////////////////
  818. // Additional helpers for WNDCLASS init
  819.  
  820. const char* AfxRegisterWndClass(UINT nClassStyle,
  821.     HCURSOR hCursor, HBRUSH hbrBackground, HICON hIcon)
  822. {
  823.     // Returns a temporary string name for the class
  824.     //  Save in a CString if you want to use it for a long time
  825.     WNDCLASS wndcls;
  826.     static char szName[64];     // 1 global string
  827.  
  828.     // generate a synthetic name for this class
  829.     if (hCursor == NULL && hbrBackground == NULL && hIcon == NULL)
  830.         wsprintf(szName, "Afx:%x", nClassStyle);
  831.     else
  832.         wsprintf(szName, "Afx:%x:%x:%x:%x", nClassStyle,
  833.             (UINT) hCursor, (UINT) hbrBackground, (UINT) hIcon);
  834.  
  835.     // see if the class already exists
  836.     if (::GetClassInfo(AfxGetInstanceHandle(), szName, &wndcls))
  837.     {
  838.         // already registered, assert everything is good
  839.         ASSERT(wndcls.style == nClassStyle);
  840.         ASSERT(wndcls.hIcon == hIcon);
  841.         ASSERT(wndcls.hCursor == hCursor);
  842.         ASSERT(wndcls.hbrBackground == hbrBackground);
  843.         return szName;
  844.     }
  845.  
  846.     // otherwise we need to register a new class
  847.     wndcls.style = nClassStyle;
  848.     wndcls.lpfnWndProc  = AfxWndProc;
  849.     wndcls.cbClsExtra = wndcls.cbWndExtra = 0;
  850.     wndcls.hInstance = AfxGetInstanceHandle();
  851.     wndcls.hIcon = hIcon;
  852.     wndcls.hCursor = hCursor;
  853.     wndcls.hbrBackground = hbrBackground;
  854.     wndcls.lpszMenuName = NULL;
  855.     wndcls.lpszClassName = szName;
  856.     if (!::RegisterClass(&wndcls))
  857.         AfxThrowResourceException();
  858.     return szName;
  859. }
  860.  
  861.  
  862.  
  863. /////////////////////////////////////////////////////////////////////////////
  864. // Dialogs have 2-phase construction
  865.  
  866. IMPLEMENT_DYNAMIC(CDialog, CWnd)
  867.  
  868. CDialog::CDialog()
  869. {
  870.     ASSERT(m_hWnd == NULL);
  871.  
  872.     m_hBrushCtlBk = NULL;
  873.     VERIFY(SetCtlBkColor(::GetSysColor(COLOR_BTNFACE)));
  874. }
  875.  
  876. CDialog::~CDialog()
  877. {
  878.     if (m_hBrushCtlBk != NULL)
  879.         ::DeleteObject(m_hBrushCtlBk);
  880.     m_hBrushCtlBk = NULL;
  881. }
  882.  
  883. #ifdef _DEBUG
  884. void
  885. CDialog::AssertValid() const
  886. {
  887.     CWnd::AssertValid();
  888.     ASSERT(m_hWnd != (HWND)1);
  889. }
  890. #endif
  891.  
  892. // Modeless
  893. BOOL
  894. CDialog::Create(LPCSTR lpTemplateName, CWnd* pParentWnd)
  895. {
  896.     if (pParentWnd == NULL)
  897.         pParentWnd = AfxGetApp()->m_pMainWnd;
  898.  
  899.     _AfxHookWindowCreate(this);
  900.     HWND hWnd = ::CreateDialog(AfxGetResourceHandle(),
  901.         lpTemplateName, pParentWnd->GetSafeHwnd(),
  902.         (DLGPROC)_AfxDlgProc);
  903.     _AfxUnhookWindowCreate();
  904.  
  905.     return (m_hWnd = hWnd) != NULL;
  906. }
  907.  
  908. BOOL
  909. CDialog::CreateIndirect(const void FAR* lpDialogTemplate,
  910.         CWnd* pParentWnd)
  911. {
  912.     if (pParentWnd == NULL)
  913.         pParentWnd = AfxGetApp()->m_pMainWnd;
  914.  
  915.     _AfxHookWindowCreate(this);
  916.     HWND hWnd = ::CreateDialogIndirect(AfxGetResourceHandle(),
  917.         lpDialogTemplate, pParentWnd->GetSafeHwnd(),
  918.         (DLGPROC)_AfxDlgProc);
  919.     _AfxUnhookWindowCreate();
  920.  
  921.     return (m_hWnd = hWnd) != NULL;
  922. }
  923.  
  924. void
  925. CDialog::OnSetFont(CFont*)
  926. {
  927.     // ignore it
  928. }
  929.  
  930. BOOL
  931. CDialog::OnInitDialog()
  932. {
  933.     return TRUE;    // set focus to first one
  934. }
  935.  
  936.  
  937. BOOL 
  938. CDialog::SetCtlBkColor(COLORREF clrCtlBk)
  939.     if (m_hBrushCtlBk != NULL)
  940.         ::DeleteObject(m_hBrushCtlBk);
  941.  
  942.     if (clrCtlBk == 0xFFFFFFFF)
  943.     {
  944.         // -1 means do not handle any WM_CTLCOLOR messages
  945.         ASSERT(m_hBrushCtlBk == NULL);
  946.         return TRUE;
  947.     }
  948.  
  949.     m_hBrushCtlBk = ::CreateSolidBrush(clrCtlBk);
  950.     return m_hBrushCtlBk != NULL ? TRUE : FALSE;
  951. }
  952.  
  953. HBRUSH 
  954. CDialog::OnCtlColor(CDC* pDC, CWnd* /* pWnd */, UINT nCtlColor)
  955. {
  956.     if (m_hBrushCtlBk == NULL || 
  957.             nCtlColor == CTLCOLOR_LISTBOX || 
  958.             nCtlColor == CTLCOLOR_EDIT || 
  959.             nCtlColor == CTLCOLOR_MSGBOX)
  960.         return (HBRUSH)Default();
  961.  
  962.     // Use new look AFX colors
  963.     // Set the background color for controls
  964.     LOGBRUSH logbrush;
  965.     if (::GetObject(m_hBrushCtlBk, sizeof(LOGBRUSH), (LPSTR)&logbrush) != 0) 
  966.     {
  967.         pDC->SetBkColor(logbrush.lbColor);
  968.     }
  969.     else
  970.     {
  971.         TRACE("Warning: couldn't set background color for CTLCOLOR\n");
  972.     }
  973.     return m_hBrushCtlBk;
  974. }
  975.  
  976. BEGIN_MESSAGE_MAP(CDialog, CWnd)
  977.     ON_WM_CTLCOLOR()
  978. END_MESSAGE_MAP()
  979.  
  980. /////////////////////////////////////////////////////////////////////////////
  981. // Dialog Proc support
  982.  
  983. BOOL
  984. CDialog::PreTranslateMessage(MSG* pMsg)
  985. {
  986.     // for modeless processing (or modal)
  987.     ASSERT(m_hWnd != NULL);
  988.  
  989.     // filter both messages to dialog and from children
  990.     return ::IsDialogMessage(m_hWnd, pMsg);
  991. }
  992.  
  993. WNDPROC*
  994. CDialog::GetSuperWndProcAddr()
  995. {
  996.     static WNDPROC pfnSuper;
  997.     return &pfnSuper;
  998. }
  999.  
  1000. /////////////////////////////////////////////////////////////////////////////
  1001. // CModalDialog
  1002.  
  1003. IMPLEMENT_DYNAMIC(CModalDialog, CDialog)
  1004.  
  1005. BEGIN_MESSAGE_MAP(CModalDialog, CDialog)
  1006.     ON_COMMAND(IDOK, OnOK)
  1007.     ON_COMMAND(IDCANCEL, OnCancel)
  1008. END_MESSAGE_MAP()
  1009.  
  1010. // Constructors just save parameters
  1011. CModalDialog::CModalDialog(LPCSTR lpTemplateName, CWnd* pParentWnd)
  1012. {
  1013.     m_lpDialogTemplate = lpTemplateName;
  1014.     m_hDialogTemplate = NULL;
  1015.     m_pParentWnd = pParentWnd;
  1016. }
  1017.  
  1018. CModalDialog::CModalDialog(UINT nIDTemplate, CWnd* pParentWnd)
  1019. {
  1020.     m_lpDialogTemplate = MAKEINTRESOURCE(nIDTemplate);
  1021.     m_hDialogTemplate = NULL;
  1022.     m_pParentWnd = pParentWnd;
  1023. }
  1024.  
  1025. BOOL
  1026. CModalDialog::CreateIndirect(HANDLE hDialogTemplate)
  1027. {
  1028.     // must be called on an empty constructed CModalDialog
  1029.     ASSERT(m_lpDialogTemplate == NULL);
  1030.     ASSERT(m_hDialogTemplate == NULL);
  1031.  
  1032.     m_hDialogTemplate = hDialogTemplate;
  1033.     return TRUE;        // always ok (DoModal actually brings up dialog)
  1034. }
  1035.  
  1036. #ifdef _DEBUG
  1037. void
  1038. CModalDialog::AssertValid() const
  1039. {
  1040.     CDialog::AssertValid();
  1041. }
  1042.  
  1043. void
  1044. CModalDialog::Dump(CDumpContext& dc) const
  1045. {
  1046.     CDialog::Dump(dc);
  1047.     dc << "\nm_lpDialogTemplate = " << m_lpDialogTemplate << "\n";
  1048.     dc << "m_hDialogTemplate = " << m_hDialogTemplate << "\n";
  1049.     dc << "m_pParentWnd = " << (void *)m_pParentWnd;
  1050. }
  1051. #endif
  1052.  
  1053. int
  1054. CModalDialog::DoModal()
  1055. {
  1056.     HWND    hWndParent;
  1057.     int     nResult;
  1058.  
  1059.     // can be constructed with a resource template or CreateIndirect
  1060.     ASSERT(m_lpDialogTemplate != NULL || m_hDialogTemplate != NULL);
  1061.  
  1062.     // find parent HWND
  1063.     if (m_pParentWnd != NULL)
  1064.         hWndParent = m_pParentWnd->m_hWnd;
  1065.     else
  1066.         hWndParent = AfxGetApp()->m_pMainWnd->GetSafeHwnd();
  1067.  
  1068.     _AfxHookWindowCreate(this);
  1069.     if (m_lpDialogTemplate != NULL)
  1070.     {
  1071.         nResult = ::DialogBox(AfxGetResourceHandle(), m_lpDialogTemplate,
  1072.             hWndParent, (DLGPROC)_AfxDlgProc);
  1073.     }
  1074.     else
  1075.     {
  1076.         nResult = ::DialogBoxIndirect(AfxGetResourceHandle(), m_hDialogTemplate,
  1077.             hWndParent, (DLGPROC)_AfxDlgProc);
  1078.     }
  1079.  
  1080.     _AfxUnhookWindowCreate();   // just in case
  1081.     Detach();               // just in case
  1082.     return nResult;
  1083. }
  1084.  
  1085. /////////////////////////////////////////////////////////////////////////////
  1086. // Standard CModalDialog implementation
  1087.  
  1088. void
  1089. CModalDialog::OnOK()
  1090. {
  1091.     EndDialog(IDOK);
  1092. }
  1093.  
  1094. void
  1095. CModalDialog::OnCancel()
  1096. {
  1097.     EndDialog(IDCANCEL);
  1098. }
  1099.  
  1100. /////////////////////////////////////////////////////////////////////////////
  1101. // CRect for creating windows with the default position/size
  1102. const CRect NEAR CFrameWnd::rectDefault(CW_USEDEFAULT, CW_USEDEFAULT,
  1103.     0 /* 2*CW_USEDEFAULT */, 0 /* 2*CW_USEDEFAULT */);
  1104.  
  1105. // CWnds for setting z-order with SetWindowPos's pWndInsertAfter parameter
  1106. const CWnd NEAR CWnd::wndTop((HWND)0);
  1107. const CWnd NEAR CWnd::wndBottom((HWND)1);
  1108. const CWnd NEAR CWnd::wndTopMost((HWND)-1);
  1109. const CWnd NEAR CWnd::wndNoTopMost((HWND)-2);
  1110.  
  1111. /////////////////////////////////////////////////////////////////////////////
  1112. // Message table implementation
  1113.  
  1114. CMessageMap CWnd::messageMap =
  1115. {
  1116.     NULL,           // end of chain of message maps
  1117.     (CMessageEntry FAR*) &CWnd::_messageEntries
  1118. };
  1119.  
  1120. CMessageMap* CWnd::GetMessageMap() const
  1121. {
  1122.     return &CWnd::messageMap;
  1123. }
  1124.  
  1125.  
  1126. CMessageEntry BASED_CODE CWnd::_messageEntries[] =
  1127. {
  1128.     ON_WM_COMPAREITEM()
  1129.     ON_WM_MEASUREITEM()
  1130.     ON_WM_DRAWITEM()
  1131.     ON_WM_DELETEITEM()
  1132.     ON_WM_CTLCOLOR()
  1133.     ON_WM_DESTROY()
  1134.     ON_WM_NCDESTROY()
  1135.  
  1136.     { 0, 0, AfxSig_end, (AFX_PMSG)0 }
  1137. };
  1138.  
  1139. union MessageMapFunctions
  1140. {
  1141.     AFX_PMSG pfn;   // generic member function pointer
  1142.  
  1143.     // specific type safe variants
  1144.     BOOL    (CWnd::*pfn_bD)(CDC *);
  1145.     BOOL    (CWnd::*pfn_bb)(BOOL);
  1146.     BOOL    (CWnd::*pfn_bWww)(CWnd*, UINT, UINT);
  1147.     HBRUSH  (CWnd::*pfn_hDWw)(CDC *, CWnd*, UINT);
  1148.     int     (CWnd::*pfn_iwWw)(UINT, CWnd*, UINT);
  1149.     int     (CWnd::*pfn_iWww)(CWnd*, UINT, UINT);
  1150.     int     (CWnd::*pfn_is)(LPSTR);
  1151.     LONG    (CWnd::*pfn_lwl)(UINT, LONG);
  1152.     LONG    (CWnd::*pfn_lwwM)(UINT, UINT, CMenu *);
  1153.     void    (CWnd::*pfn_vv)(void);
  1154.  
  1155.     void    (CWnd::*pfn_vw)(UINT);
  1156.     void    (CWnd::*pfn_vww)(UINT, UINT);
  1157.     void    (CWnd::*pfn_vvii)(int, int);
  1158.     void    (CWnd::*pfn_vwww)(UINT, UINT, UINT);
  1159.     void    (CWnd::*pfn_vwii)(UINT, int, int);
  1160.     void    (CWnd::*pfn_vwl)(UINT, LONG);
  1161.     void    (CWnd::*pfn_vbWW)(BOOL, CWnd*, CWnd*);
  1162.     void    (CWnd::*pfn_vD)(CDC *);
  1163.     void    (CWnd::*pfn_vM)(CMenu *);
  1164.     void    (CWnd::*pfn_vMwb)(CMenu *, UINT, BOOL);
  1165.  
  1166.     void    (CWnd::*pfn_vW)(CWnd*);
  1167.     void    (CWnd::*pfn_vWww)(CWnd*, UINT, UINT);
  1168.     void    (CWnd::*pfn_vWh)(CWnd*, HANDLE);
  1169.     void    (CWnd::*pfn_vwW)(UINT, CWnd*);
  1170.     void    (CWnd::*pfn_vwWb)(UINT, CWnd*, BOOL);
  1171.     void    (CWnd::*pfn_vwwW)(UINT, UINT, CWnd*);
  1172.     void    (CWnd::*pfn_vs)(LPSTR);
  1173.     UINT    (CWnd::*pfn_wp)(CPoint);
  1174.     UINT    (CWnd::*pfn_wv)(void);
  1175.     BOOL    (CWnd::*pfn_bh)(HANDLE);
  1176.     void    (CWnd::*pfn_vPOS)(WINDOWPOS FAR*);
  1177.     void    (CWnd::*pfn_vCALC)(NCCALCSIZE_PARAMS FAR*);
  1178. };
  1179.  
  1180. /////////////////////////////////////////////////////////////////////////////
  1181. // Routines for fast search of message maps
  1182.  
  1183.  
  1184. // Hand tuned routine
  1185.  
  1186. #pragma optimize("qgel", off) // assembler cannot be globally optimized
  1187.  
  1188. static CMessageEntry FAR* NEAR
  1189. FindMessageEntry(CMessageEntry FAR* lpEntry, UINT nMsg, UINT nID)
  1190. {
  1191.     _asm
  1192.     {
  1193.                 LES     BX,lpEntry
  1194.                 MOV     AX,nMsg
  1195.                 MOV     DX,nID
  1196.         __loop:
  1197.                 MOV     CX,WORD PTR ES:[BX+4]   ; nSig (0 => end)
  1198.                 JCXZ    __failed
  1199.                 CMP     AX,WORD PTR ES:[BX]     ; nMessage
  1200.                 JE      __found_1
  1201.         __next:
  1202.                 ADD     BX,SIZE CMessageEntry
  1203.                 JMP     __loop
  1204.         __found_1:
  1205.                 CMP     DX,WORD PTR ES:[BX+2]   ; nID
  1206.                 JNE     __next
  1207.         // found a match
  1208.                 MOV     WORD PTR lpEntry,BX
  1209.                 MOV     WORD PTR lpEntry+2,ES
  1210.                 JMP     __end
  1211.         __failed:
  1212.                 XOR     AX,AX
  1213.                 MOV     WORD PTR lpEntry,AX
  1214.                 MOV     WORD PTR lpEntry+2,AX
  1215.         __end:
  1216.     }
  1217.     return lpEntry;
  1218. }
  1219.  
  1220. #pragma optimize("", on)    // return to default optimizations
  1221.  
  1222.  
  1223. /////////////////////////////////////////////////////////////////////////////
  1224.  
  1225. #ifndef iHashMax
  1226. // iHashMax must be a power of two
  1227.     #ifdef _NEARDATA
  1228.         #define iHashMax 64
  1229.     #else
  1230.         #define iHashMax 256
  1231.     #endif
  1232. #endif
  1233.  
  1234. struct MsgCache
  1235. {
  1236.     UINT nMsg;
  1237.     CMessageEntry FAR* lpEntry;
  1238.     CMessageMap* pMessageMap;
  1239. };
  1240.  
  1241. MsgCache _afxMsgCache[iHashMax];
  1242.  
  1243. LONG
  1244. CWnd::WindowProc(UINT nMsg, UINT wParam, LONG lParam)
  1245. {
  1246.     register CMessageMap* pMessageMap;
  1247.     CMessageEntry FAR* lpEntry;
  1248.  
  1249.     if (nMsg == WM_COMMAND) // special case for commands
  1250.     {
  1251.         if (OnCommand(wParam, lParam))
  1252.             return 1L; // command handled
  1253.         else 
  1254.             return (LONG)DefWindowProc(nMsg, wParam, lParam); // call default handler
  1255.     }
  1256.  
  1257.     pMessageMap = GetMessageMap();
  1258.     UINT iHash = (_AFX_FP_OFF(pMessageMap) ^ nMsg) & (iHashMax-1);
  1259.     MsgCache& msgCache = _afxMsgCache[iHash];
  1260.  
  1261.     if (nMsg == msgCache.nMsg && pMessageMap == msgCache.pMessageMap)
  1262.     {
  1263.         // Cache hit
  1264.         lpEntry = msgCache.lpEntry;
  1265.         if (lpEntry == NULL)
  1266.             return (LONG)DefWindowProc(nMsg, wParam, lParam);
  1267.         else if (nMsg < 0xC000)
  1268.             goto LDispatch;
  1269.         else
  1270.             goto LDispatchRegistered;
  1271.     }
  1272.     else
  1273.     {
  1274.         // not in cache, look for it
  1275.         msgCache.nMsg = nMsg;
  1276.         msgCache.pMessageMap = pMessageMap;
  1277.  
  1278.         for (/* pMessageMap already init'ed */; pMessageMap != NULL;
  1279.             pMessageMap = pMessageMap->pBaseMessageMap)
  1280.         {
  1281.             // This may loop forever if the message maps are not properly
  1282.             // chained together.  Make sure each window class's message map
  1283.             // points to the base window class's message map.
  1284.  
  1285.             if (nMsg < 0xC000)
  1286.             {
  1287.                 // constant window message
  1288.                 if ((lpEntry = FindMessageEntry(pMessageMap->lpEntries,
  1289.                     nMsg, 0)) != NULL)
  1290.                 {
  1291.                     msgCache.lpEntry = lpEntry;
  1292.                     goto LDispatch;
  1293.                 }
  1294.             }
  1295.             else
  1296.             {
  1297.                 // registered windows message
  1298.                 lpEntry = pMessageMap->lpEntries;
  1299.  
  1300.                 while ((lpEntry = FindMessageEntry(lpEntry, 0xC000, 0)) != NULL)
  1301.                 {
  1302.                     UINT NEAR* pnID = (UINT NEAR*)(lpEntry->nSig);
  1303.                     ASSERT(*pnID >= 0xC000);
  1304.                         // must be successfully registered
  1305.                     if (*pnID == nMsg)
  1306.                     {
  1307.                         msgCache.lpEntry = lpEntry;
  1308.                         goto LDispatchRegistered;
  1309.                     }
  1310.                     lpEntry++;      // keep looking past this one
  1311.                 }
  1312.             }
  1313.         }
  1314.  
  1315.         msgCache.lpEntry = NULL;
  1316.         return DefWindowProc(nMsg, wParam, lParam);
  1317.     }
  1318.     ASSERT(FALSE);      // not reached
  1319.  
  1320.  
  1321. LDispatch:
  1322.     ASSERT(nMsg < 0xC000);
  1323.     union MessageMapFunctions mmf;
  1324.     mmf.pfn = lpEntry->pfn;
  1325.  
  1326.     switch (lpEntry->nSig)
  1327.     {
  1328.     default:
  1329.         ASSERT(FALSE);
  1330.         return 0;
  1331.  
  1332.     case AfxSig_bD:
  1333.         return (this->*mmf.pfn_bD)(CDC::FromHandle((HDC)wParam));
  1334.  
  1335.     case AfxSig_bb:
  1336.         return (this->*mmf.pfn_bb)((BOOL)wParam);
  1337.  
  1338.     case AfxSig_bWww:
  1339.         return (this->*mmf.pfn_bWww)(CWnd::FromHandle((HWND)wParam),
  1340.             LOWORD(lParam), HIWORD(lParam));
  1341.  
  1342.     case AfxSig_hDWw:
  1343.         return (LONG)(UINT)(this->*mmf.pfn_hDWw)(CDC::FromHandle((HDC)wParam),
  1344.             CWnd::FromHandle((HWND)LOWORD(lParam)), HIWORD(lParam));
  1345.  
  1346.     case AfxSig_iwWw:
  1347.         return (this->*mmf.pfn_iwWw)(wParam, CWnd::FromHandle((HWND)LOWORD(lParam)),
  1348.             HIWORD(lParam));
  1349.  
  1350.     case AfxSig_iWww:
  1351.         return (this->*mmf.pfn_iWww)(CWnd::FromHandle((HWND)wParam),
  1352.             LOWORD(lParam), HIWORD(lParam));
  1353.  
  1354.     case AfxSig_is:
  1355.         return (this->*mmf.pfn_is)((LPSTR)lParam);
  1356.  
  1357.     case AfxSig_lwl:
  1358.         return (this->*mmf.pfn_lwl)(wParam, lParam);
  1359.  
  1360.     case AfxSig_lwwM:
  1361.         return (this->*mmf.pfn_lwwM)(wParam, LOWORD(lParam),
  1362.             CMenu::FromHandle((HMENU)HIWORD(lParam)));
  1363.  
  1364.     case AfxSig_vv:
  1365.         (this->*mmf.pfn_vv)();
  1366.         return 0;
  1367.  
  1368.  
  1369.     case AfxSig_vw: // AfxSig_vb:
  1370.         (this->*mmf.pfn_vw)(wParam);
  1371.         return 0;
  1372.  
  1373.     case AfxSig_vww:
  1374.         (this->*mmf.pfn_vww)(wParam, LOWORD(lParam));
  1375.         return 0;
  1376.  
  1377.     case AfxSig_vvii:
  1378.         (this->*mmf.pfn_vvii)(LOWORD(lParam), HIWORD(lParam));
  1379.         return 0;
  1380.  
  1381.     case AfxSig_vwww:
  1382.         (this->*mmf.pfn_vwww)(wParam, LOWORD(lParam), HIWORD(lParam));
  1383.         return 0;
  1384.  
  1385.     case AfxSig_vwii:
  1386.         (this->*mmf.pfn_vwii)(wParam, LOWORD(lParam), HIWORD(lParam));
  1387.         return 0;
  1388.  
  1389.     case AfxSig_vwl:
  1390.         (this->*mmf.pfn_vwl)(wParam, lParam);
  1391.         return 0;
  1392.  
  1393.     case AfxSig_vbWW:
  1394.         (this->*mmf.pfn_vbWW)((BOOL)wParam,
  1395.             CWnd::FromHandle((HWND)LOWORD(lParam)),
  1396.             CWnd::FromHandle((HWND)HIWORD(lParam)));
  1397.         return 0;
  1398.  
  1399.     case AfxSig_vD:
  1400.         (this->*mmf.pfn_vD)(CDC::FromHandle((HDC)wParam));
  1401.         return 0;
  1402.  
  1403.     case AfxSig_vM:
  1404.         (this->*mmf.pfn_vM)(CMenu::FromHandle((HMENU)wParam));
  1405.         return 0;
  1406.  
  1407.     case AfxSig_vMwb:
  1408.         (this->*mmf.pfn_vMwb)(CMenu::FromHandle((HMENU)wParam),
  1409.             LOWORD(lParam), (BOOL)HIWORD(lParam));
  1410.         return 0;
  1411.  
  1412.  
  1413.     case AfxSig_vW:
  1414.         (this->*mmf.pfn_vW)(CWnd::FromHandle((HWND)wParam));
  1415.         return 0;
  1416.  
  1417.     case AfxSig_vWww:
  1418.         (this->*mmf.pfn_vWww)(CWnd::FromHandle((HWND)wParam), LOWORD(lParam),
  1419.             HIWORD(lParam));
  1420.         return 0;
  1421.  
  1422.     case AfxSig_vWh:
  1423.         (this->*mmf.pfn_vWh)(CWnd::FromHandle((HWND)wParam),
  1424.                 (HANDLE)LOWORD(lParam));
  1425.         return 0;
  1426.  
  1427.     case AfxSig_vwW:
  1428.         (this->*mmf.pfn_vwW)(wParam, CWnd::FromHandle((HWND)LOWORD(lParam)));
  1429.         return 0;
  1430.  
  1431.     case AfxSig_vwWb:
  1432.         (this->*mmf.pfn_vwWb)(wParam, CWnd::FromHandle((HWND)LOWORD(lParam)),
  1433.             (BOOL)HIWORD(lParam));
  1434.         return 0;
  1435.  
  1436.     case AfxSig_vwwW:
  1437.         (this->*mmf.pfn_vwwW)(wParam, LOWORD(lParam),
  1438.             CWnd::FromHandle((HWND)HIWORD(lParam)));
  1439.         return 0;
  1440.  
  1441.     case AfxSig_vs:
  1442.         (this->*mmf.pfn_vs)((LPSTR)lParam);
  1443.         return 0;
  1444.  
  1445.     case AfxSig_wp:
  1446.         return (this->*mmf.pfn_wp)(*(CPoint*)&lParam);
  1447.  
  1448.     case AfxSig_wv: // AfxSig_bv, AfxSig_wv
  1449.         return (this->*mmf.pfn_wv)();
  1450.  
  1451.     case AfxSig_bh:
  1452.         return (this->*mmf.pfn_bh)((HANDLE)wParam);
  1453.  
  1454.     case AfxSig_vCALC:
  1455.         (this->*mmf.pfn_vCALC)((NCCALCSIZE_PARAMS FAR*)lParam);
  1456.         return 0;
  1457.  
  1458.     case AfxSig_vPOS:
  1459.         (this->*mmf.pfn_vPOS)((WINDOWPOS FAR*)lParam);
  1460.         return 0;
  1461.     }
  1462.     ASSERT(FALSE);      // not reached
  1463.  
  1464. LDispatchRegistered:    // for registered windows messages
  1465.     ASSERT(nMsg >= 0xC000);
  1466.     mmf.pfn = lpEntry->pfn;
  1467.     return (this->*mmf.pfn_lwl)(wParam, lParam);
  1468. }
  1469.  
  1470. BOOL CWnd::OnCommand(UINT wParam, LONG lParam)
  1471. {
  1472.     UINT nID = wParam;
  1473.     HWND hWndCtrl = (HWND)LOWORD(lParam);
  1474.     UINT nNotifyCode = HIWORD(lParam);  // control specific
  1475.     if (nID == 0)
  1476.         return FALSE;       // 0 control IDs are not allowed !
  1477.  
  1478.     // default routing for command messages (through closure table)
  1479.     if (hWndCtrl == NULL)
  1480.         nNotifyCode = 0;        // accelerators are not special
  1481.  
  1482.     // check in message map table for matching control ID
  1483.     register CMessageMap* pMessageMap;
  1484.     register CMessageEntry FAR* lpEntry;
  1485.  
  1486.     for (pMessageMap = GetMessageMap(); pMessageMap != NULL;
  1487.       pMessageMap = pMessageMap->pBaseMessageMap)
  1488.     {
  1489.         if ((lpEntry = FindMessageEntry(pMessageMap->lpEntries,
  1490.           nNotifyCode, nID)) != NULL)
  1491.         {
  1492. #ifdef _DEBUG
  1493.             // diagnostic trace reporting of command notifications
  1494.             if (afxTraceFlags & 8)  // if command reporting
  1495.             {
  1496.                 if (nNotifyCode == 0)
  1497.                 {
  1498.                     TRACE("SENDING command %d to %s window\n", nID,
  1499.                         GetRuntimeClass()->m_pszClassName);
  1500.                 }
  1501.                 else if (afxTraceFlags & 4) // if verbose windows messages
  1502.                 {
  1503.                     TRACE("SENDING control notification %d from control id %d "
  1504.                         "to %s window\n", nNotifyCode, nID,
  1505.                         GetRuntimeClass()->m_pszClassName);
  1506.                 }
  1507.             }
  1508. #endif
  1509.             // dispatch it
  1510.             (this->*lpEntry->pfn)();
  1511.             return TRUE;    // handled
  1512.         }
  1513.     }
  1514.  
  1515. #ifdef _DEBUG
  1516.     if (afxTraceFlags & 8)
  1517.     {
  1518.         if (nNotifyCode == 0)
  1519.         {
  1520.             TRACE("IGNORING command %d sent to %s window\n", nID,
  1521.                     GetRuntimeClass()->m_pszClassName);
  1522.         }
  1523.         else if (afxTraceFlags & 4) // if verbose windows messages
  1524.         {
  1525.             TRACE("IGNORING control notification %d from control id %d "
  1526.                 "to %s window\n", nNotifyCode, nID,
  1527.                 GetRuntimeClass()->m_pszClassName);
  1528.         }
  1529.     }
  1530. #endif
  1531.  
  1532.     return FALSE;       // not handled
  1533. }
  1534.  
  1535.  
  1536.  
  1537. /////////////////////////////////////////////////////////////////////////////
  1538.