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

  1. // This is a part of the Microsoft Foundation Classes C++ library.
  2. // Copyright (C) 1992-1998 Microsoft Corporation
  3. // All rights reserved.
  4. //
  5. // This source code is only intended as a supplement to the
  6. // Microsoft Foundation Classes Reference and related
  7. // electronic documentation provided with the library.
  8. // See these sources for detailed information regarding the
  9. // Microsoft Foundation Classes product.
  10.  
  11. #include "stdafx.h"
  12.  
  13. #ifdef AFX_CMNCTL_SEG
  14. #pragma code_seg(AFX_CMNCTL_SEG)
  15. #endif
  16.  
  17. #ifdef _DEBUG
  18. #undef THIS_FILE
  19. static char THIS_FILE[] = __FILE__;
  20. #endif
  21.  
  22. #define new DEBUG_NEW
  23.  
  24. #ifndef _AFX_NO_OLE_SUPPORT
  25. extern "C"
  26. {
  27. HIMAGELIST WINAPI ImageList_Read(LPSTREAM pstm);
  28. BOOL       WINAPI ImageList_Write(HIMAGELIST himl, LPSTREAM pstm);
  29. }
  30. #endif
  31.  
  32. /////////////////////////////////////////////////////////////////////////////
  33. // CDragListBox
  34.  
  35. CDragListBox::~CDragListBox()
  36. {
  37.     DestroyWindow();
  38. }
  39.  
  40. void CDragListBox::PreSubclassWindow()
  41. {
  42.     ASSERT(::IsWindow(m_hWnd));
  43.     ASSERT((GetStyle() & (LBS_MULTIPLESEL|LBS_SORT)) == 0);
  44.     MakeDragList(m_hWnd);
  45. }
  46.  
  47. BOOL CDragListBox::BeginDrag(CPoint pt)
  48. {
  49.     m_nLast = -1;
  50.     DrawInsert(ItemFromPt(pt));
  51.     return TRUE;
  52. }
  53.  
  54. void CDragListBox::CancelDrag(CPoint)
  55. {
  56.     DrawInsert(-1);
  57. }
  58.  
  59. UINT CDragListBox::Dragging(CPoint pt)
  60. {
  61.     int nIndex = ItemFromPt(pt, FALSE); // don't allow scrolling just yet
  62.     DrawInsert(nIndex);
  63.     ItemFromPt(pt);
  64.     return (nIndex == LB_ERR) ? DL_STOPCURSOR : DL_MOVECURSOR;
  65. }
  66.  
  67. void CDragListBox::Dropped(int nSrcIndex, CPoint pt)
  68. {
  69.     ASSERT(!(GetStyle() & (LBS_OWNERDRAWFIXED|LBS_OWNERDRAWVARIABLE)) ||
  70.         (GetStyle() & LBS_HASSTRINGS));
  71.  
  72.     DrawInsert(-1);
  73.     int nDestIndex = ItemFromPt(pt);
  74.  
  75.     if (nSrcIndex == -1 || nDestIndex == -1)
  76.         return;
  77.     if (nDestIndex == nSrcIndex || nDestIndex == nSrcIndex+1)
  78.         return; //didn't move
  79.     CString str;
  80.     DWORD dwData;
  81.     GetText(nSrcIndex, str);
  82.     dwData = GetItemData(nSrcIndex);
  83.     DeleteString(nSrcIndex);
  84.     if (nSrcIndex < nDestIndex)
  85.         nDestIndex--;
  86.     nDestIndex = InsertString(nDestIndex, str);
  87.     SetItemData(nDestIndex, dwData);
  88.     SetCurSel(nDestIndex);
  89. }
  90.  
  91. void CDragListBox::DrawInsert(int nIndex)
  92. {
  93.     if (m_nLast != nIndex)
  94.     {
  95.         DrawSingle(m_nLast);
  96.         DrawSingle(nIndex);
  97.         m_nLast = nIndex;
  98.     }
  99. }
  100.  
  101. void CDragListBox::DrawSingle(int nIndex)
  102. {
  103.     if (nIndex == -1)
  104.         return;
  105.     CBrush* pBrush = CDC::GetHalftoneBrush();
  106.     CRect rect;
  107.     GetClientRect(&rect);
  108.     CRgn rgn;
  109.     rgn.CreateRectRgnIndirect(&rect);
  110.  
  111.     CDC* pDC = GetDC();
  112.     // prevent drawing outside of listbox
  113.     // this can happen at the top of the listbox since the listbox's DC is the
  114.     // parent's DC
  115.     pDC->SelectClipRgn(&rgn);
  116.  
  117.     GetItemRect(nIndex, &rect);
  118.     rect.bottom = rect.top+2;
  119.     rect.top -= 2;
  120.     CBrush* pBrushOld = pDC->SelectObject(pBrush);
  121.     //draw main line
  122.     pDC->PatBlt(rect.left, rect.top, rect.Width(), rect.Height(), PATINVERT);
  123.  
  124.     pDC->SelectObject(pBrushOld);
  125.     ReleaseDC(pDC);
  126. }
  127.  
  128. BOOL CDragListBox::OnChildNotify(UINT nMessage, WPARAM wParam, LPARAM lParam, LRESULT* pResult)
  129. {
  130.     if (nMessage != m_nMsgDragList)
  131.         return CListBox::OnChildNotify(nMessage, wParam, lParam, pResult);
  132.  
  133.     ASSERT(pResult != NULL);
  134.     LPDRAGLISTINFO pInfo = (LPDRAGLISTINFO)lParam;
  135.     ASSERT(pInfo != NULL);
  136.     switch (pInfo->uNotification)
  137.     {
  138.     case DL_BEGINDRAG:
  139.         *pResult = BeginDrag(pInfo->ptCursor);
  140.         break;
  141.     case DL_CANCELDRAG:
  142.         CancelDrag(pInfo->ptCursor);
  143.         break;
  144.     case DL_DRAGGING:
  145.         *pResult = Dragging(pInfo->ptCursor);
  146.         break;
  147.     case DL_DROPPED:
  148.         Dropped(GetCurSel(), pInfo->ptCursor);
  149.         break;
  150.     }
  151.     return TRUE;
  152. }
  153.  
  154. /////////////////////////////////////////////////////////////////////////////
  155. // CToolBarCtrl
  156.  
  157. BEGIN_MESSAGE_MAP(CToolBarCtrl, CWnd)
  158.     //{{AFX_MSG_MAP(CToolBarCtrl)
  159.     ON_WM_CREATE()
  160.     //}}AFX_MSG_MAP
  161. END_MESSAGE_MAP()
  162.  
  163. BOOL CToolBarCtrl::Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd,
  164.     UINT nID)
  165. {
  166.     // initialize common controls
  167.     VERIFY(AfxDeferRegisterClass(AFX_WNDCOMMCTL_BAR_REG));
  168.  
  169.     CWnd* pWnd = this;
  170.     return pWnd->Create(TOOLBARCLASSNAME, NULL, dwStyle, rect, pParentWnd, nID);
  171. }
  172.  
  173. CToolBarCtrl::~CToolBarCtrl()
  174. {
  175.     DestroyWindow();
  176. }
  177.  
  178. int CToolBarCtrl::AddBitmap(int nNumButtons, CBitmap* pBitmap)
  179. {
  180.     ASSERT(::IsWindow(m_hWnd));
  181.     TBADDBITMAP tbab;
  182.     tbab.hInst = NULL;
  183.     tbab.nID = (UINT)pBitmap->GetSafeHandle();
  184.     return (int) ::SendMessage(m_hWnd, TB_ADDBITMAP, (WPARAM)nNumButtons,
  185.         (LPARAM)&tbab);
  186. }
  187.  
  188. int CToolBarCtrl::AddBitmap(int nNumButtons, UINT nBitmapID)
  189. {
  190.     ASSERT(::IsWindow(m_hWnd));
  191.     TBADDBITMAP tbab;
  192.     tbab.hInst = AfxFindResourceHandle((LPCTSTR)nBitmapID, RT_BITMAP);
  193.     ASSERT(tbab.hInst != NULL);
  194.     tbab.nID = nBitmapID;
  195.     return (int) ::SendMessage(m_hWnd, TB_ADDBITMAP, (WPARAM)nNumButtons,
  196.         (LPARAM)&tbab);
  197. }
  198.  
  199. void CToolBarCtrl::SaveState(HKEY hKeyRoot, LPCTSTR lpszSubKey,
  200.     LPCTSTR lpszValueName)
  201. {
  202.     ASSERT(::IsWindow(m_hWnd));
  203.     TBSAVEPARAMS tbs;
  204.     tbs.hkr = hKeyRoot;
  205.     tbs.pszSubKey = lpszSubKey;
  206.     tbs.pszValueName = lpszValueName;
  207.     ::SendMessage(m_hWnd, TB_SAVERESTORE, (WPARAM)TRUE, (LPARAM)&tbs);
  208. }
  209.  
  210. void CToolBarCtrl::RestoreState(HKEY hKeyRoot, LPCTSTR lpszSubKey,
  211.     LPCTSTR lpszValueName)
  212. {
  213.     ASSERT(::IsWindow(m_hWnd));
  214.     TBSAVEPARAMS tbs;
  215.     tbs.hkr = hKeyRoot;
  216.     tbs.pszSubKey = lpszSubKey;
  217.     tbs.pszValueName = lpszValueName;
  218.     ::SendMessage(m_hWnd, TB_SAVERESTORE, (WPARAM)FALSE, (LPARAM)&tbs);
  219. }
  220.  
  221. int CToolBarCtrl::AddString(UINT nStringID)
  222. {
  223.     ASSERT(::IsWindow(m_hWnd));
  224.     HINSTANCE hInst = AfxFindResourceHandle(MAKEINTRESOURCE((nStringID>>4)+1),
  225.         RT_STRING);
  226.     ASSERT(hInst != NULL);
  227.     return (int)::SendMessage(m_hWnd, TB_ADDSTRING, (WPARAM)hInst, nStringID);
  228. }
  229.  
  230. int CToolBarCtrl::OnCreate(LPCREATESTRUCT lpcs)
  231. {
  232.     if (CWnd::OnCreate(lpcs) == -1)
  233.         return -1;
  234.     SetButtonStructSize(sizeof(TBBUTTON));
  235.     return 0;
  236. }
  237.  
  238. HRESULT CToolBarCtrl::GetDropTarget(IDropTarget** ppDropTarget) const
  239. {
  240.     ASSERT(::IsWindow(m_hWnd));
  241.     ASSERT(ppDropTarget);
  242.     return (HRESULT) ::SendMessage(m_hWnd, TB_GETOBJECT, (WPARAM)&IID_IDropTarget, (LPARAM)ppDropTarget);
  243. }
  244.  
  245. /////////////////////////////////////////////////////////////////////////////
  246. // CStatusBarCtrl
  247.  
  248. BOOL CStatusBarCtrl::Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd,
  249.     UINT nID)
  250. {
  251.     // initialize common controls
  252.     VERIFY(AfxDeferRegisterClass(AFX_WNDCOMMCTL_BAR_REG));
  253.  
  254.     CWnd* pWnd = this;
  255.     return pWnd->Create(STATUSCLASSNAME, NULL, dwStyle, rect, pParentWnd, nID);
  256. }
  257.  
  258. CStatusBarCtrl::~CStatusBarCtrl()
  259. {
  260.     DestroyWindow();
  261. }
  262.  
  263. int CStatusBarCtrl::GetText(LPCTSTR lpszText, int nPane, int* pType) const
  264. {
  265.     ASSERT(::IsWindow(m_hWnd));
  266.     ASSERT(nPane < 256);
  267.     DWORD dw = ::SendMessage(m_hWnd, SB_GETTEXT, (WPARAM)nPane,
  268.         (LPARAM)lpszText);
  269.     if (pType != NULL)
  270.         *pType = HIWORD(dw);
  271.     return LOWORD(dw);
  272. }
  273.  
  274. CString CStatusBarCtrl::GetText(int nPane, int* pType) const
  275. {
  276.     ASSERT(::IsWindow(m_hWnd));
  277.     ASSERT(nPane < 256);
  278.     int nLength = LOWORD(::SendMessage(m_hWnd, SB_GETTEXTLENGTH,
  279.         (WPARAM)nPane, 0L));
  280.     CString str;
  281.     DWORD dw = ::SendMessage(m_hWnd, SB_GETTEXT, (WPARAM)nPane,
  282.         (LPARAM)str.GetBufferSetLength(nLength+1));
  283.     str.ReleaseBuffer();
  284.     if (pType != NULL)
  285.         *pType = HIWORD(dw);
  286.     return str;
  287. }
  288.  
  289. int CStatusBarCtrl::GetTextLength(int nPane, int* pType) const
  290. {
  291.     ASSERT(::IsWindow(m_hWnd));
  292.     ASSERT(nPane < 256);
  293.     DWORD dw = ::SendMessage(m_hWnd, SB_GETTEXTLENGTH, (WPARAM)nPane, 0L);
  294.     if (pType != NULL)
  295.         *pType = HIWORD(dw);
  296.     return LOWORD(dw);
  297. }
  298.  
  299. CString CStatusBarCtrl::GetTipText(int nPane) const
  300. {
  301.     ASSERT(::IsWindow(m_hWnd));
  302.     ASSERT(nPane < 256);
  303.     TCHAR buf[256];
  304.     ::SendMessage(m_hWnd, SB_GETTIPTEXT, MAKEWPARAM(nPane, 256), (LPARAM)buf);
  305.     return CString(buf);
  306. }
  307.  
  308. BOOL CStatusBarCtrl::GetBorders(int& nHorz, int& nVert, int& nSpacing) const
  309. {
  310.     ASSERT(::IsWindow(m_hWnd));
  311.     int borders[3];
  312.     BOOL bResult = (BOOL)::SendMessage(m_hWnd, SB_GETBORDERS, 0,
  313.         (LPARAM)&borders);
  314.     if (bResult)
  315.     {
  316.         nHorz = borders[0];
  317.         nVert = borders[1];
  318.         nSpacing = borders[2];
  319.     }
  320.     return bResult;
  321. }
  322.  
  323. void CStatusBarCtrl::DrawItem(LPDRAWITEMSTRUCT)
  324. {
  325.     ASSERT(FALSE);  // must override for self draw status bars
  326. }
  327.  
  328. BOOL CStatusBarCtrl::OnChildNotify(UINT message, WPARAM wParam, LPARAM lParam,
  329.     LRESULT* pResult)
  330. {
  331.     if (message != WM_DRAWITEM)
  332.         return CWnd::OnChildNotify(message, wParam, lParam, pResult);
  333.  
  334.     ASSERT(pResult == NULL);       // no return value expected
  335.     UNUSED(pResult); // unused in release builds
  336.  
  337.     DrawItem((LPDRAWITEMSTRUCT)lParam);
  338.     return TRUE;
  339. }
  340.  
  341. /////////////////////////////////////////////////////////////////////////////
  342. // CListCtrl
  343.  
  344. BEGIN_MESSAGE_MAP(CListCtrl, CWnd)
  345.     //{{AFX_MSG_MAP(CListCtrl)
  346.     ON_WM_NCDESTROY()
  347.     //}}AFX_MSG_MAP
  348. END_MESSAGE_MAP()
  349.  
  350. BOOL CListCtrl::Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd,
  351.     UINT nID)
  352. {
  353.     // initialize common controls
  354.     VERIFY(AfxDeferRegisterClass(AFX_WNDCOMMCTL_LISTVIEW_REG));
  355.  
  356.     CWnd* pWnd = this;
  357.     return pWnd->Create(WC_LISTVIEW, NULL, dwStyle, rect, pParentWnd, nID);
  358. }
  359.  
  360. CListCtrl::~CListCtrl()
  361. {
  362.     DestroyWindow();
  363. }
  364.  
  365. BOOL CListCtrl::GetItemRect(int nItem, LPRECT lpRect, UINT nCode) const
  366. {
  367.     ASSERT(::IsWindow(m_hWnd));
  368.     lpRect->left = nCode;
  369.     return (BOOL) ::SendMessage(m_hWnd, LVM_GETITEMRECT, (WPARAM)nItem,
  370.         (LPARAM)lpRect);
  371. }
  372.  
  373. BOOL CListCtrl::SetItemCountEx(int iCount, DWORD dwFlags /* = LVSICF_NOINVALIDATEALL */)
  374. {
  375.     ASSERT(::IsWindow(m_hWnd));
  376.  
  377.     // can't have dwFlags on a control that isn't virutal
  378.     ASSERT(dwFlags == 0 || (GetStyle() & LVS_OWNERDATA));
  379.  
  380.     return (BOOL) ::SendMessage(m_hWnd, LVM_SETITEMCOUNT, (WPARAM) iCount,
  381.         (LPARAM) dwFlags);
  382. }
  383.  
  384. CSize CListCtrl::SetIconSpacing(int cx, int cy)
  385. {
  386.     ASSERT(::IsWindow(m_hWnd));
  387.     DWORD dwRet = (DWORD) ::SendMessage(m_hWnd, LVM_SETICONSPACING,
  388.         0, (LPARAM) MAKELONG(cx, cy));
  389.  
  390.     return CSize(dwRet);
  391. }
  392.  
  393. CSize CListCtrl::SetIconSpacing(CSize size)
  394. {
  395.     ASSERT(::IsWindow(m_hWnd));
  396.     DWORD dwRet = (DWORD) ::SendMessage(m_hWnd, LVM_SETICONSPACING,
  397.         0, (LPARAM) MAKELONG(size.cx, size.cy));
  398.  
  399.     return CSize(dwRet);
  400. }
  401.  
  402. BOOL CListCtrl::GetSubItemRect(int iItem, int iSubItem, int nArea, CRect& ref)
  403. {
  404.     ASSERT(::IsWindow(m_hWnd));
  405.     ASSERT(nArea == LVIR_BOUNDS || nArea == LVIR_ICON || nArea == LVIR_LABEL);
  406.  
  407.     RECT rect;
  408.     rect.top = iSubItem;
  409.     rect.left = nArea;
  410.     BOOL bRet = (BOOL) ::SendMessage(m_hWnd, LVM_GETSUBITEMRECT,
  411.         iItem, (LPARAM) &rect);
  412.  
  413.     if (bRet)
  414.         ref = rect;
  415.     return bRet;
  416. }
  417.  
  418. int CListCtrl::InsertColumn(int nCol, LPCTSTR lpszColumnHeading, int nFormat,
  419.     int nWidth, int nSubItem)
  420. {
  421.     LVCOLUMN column;
  422.     column.mask = LVCF_TEXT|LVCF_FMT;
  423.     column.pszText = (LPTSTR)lpszColumnHeading;
  424.     column.fmt = nFormat;
  425.     if (nWidth != -1)
  426.     {
  427.         column.mask |= LVCF_WIDTH;
  428.         column.cx = nWidth;
  429.     }
  430.     if (nSubItem != -1)
  431.     {
  432.         column.mask |= LVCF_SUBITEM;
  433.         column.iSubItem = nSubItem;
  434.     }
  435.     return CListCtrl::InsertColumn(nCol, &column);
  436. }
  437.  
  438. int CListCtrl::InsertItem(UINT nMask, int nItem, LPCTSTR lpszItem, UINT nState, UINT nStateMask,
  439.     int nImage, LPARAM lParam)
  440. {
  441.     ASSERT(::IsWindow(m_hWnd));
  442.     LVITEM item;
  443.     item.mask = nMask;
  444.     item.iItem = nItem;
  445.     item.iSubItem = 0;
  446.     item.pszText = (LPTSTR)lpszItem;
  447.     item.state = nState;
  448.     item.stateMask = nStateMask;
  449.     item.iImage = nImage;
  450.     item.lParam = lParam;
  451.     return CListCtrl::InsertItem(&item);
  452. }
  453.  
  454. int CListCtrl::HitTest(CPoint pt, UINT* pFlags) const
  455. {
  456.     ASSERT(::IsWindow(m_hWnd));
  457.     LVHITTESTINFO hti;
  458.     hti.pt = pt;
  459.     int nRes = (int) ::SendMessage(m_hWnd, LVM_HITTEST, 0, (LPARAM)&hti);
  460.     if (pFlags != NULL)
  461.         *pFlags = hti.flags;
  462.     return nRes;
  463. }
  464.  
  465. BOOL CListCtrl::SetItem(int nItem, int nSubItem, UINT nMask, LPCTSTR lpszItem,
  466.     int nImage, UINT nState, UINT nStateMask, LPARAM lParam)
  467. {
  468.     ASSERT(::IsWindow(m_hWnd));
  469.     ASSERT((GetStyle() & LVS_OWNERDATA)==0);
  470.     LVITEM lvi;
  471.     lvi.mask = nMask;
  472.     lvi.iItem = nItem;
  473.     lvi.iSubItem = nSubItem;
  474.     lvi.stateMask = nStateMask;
  475.     lvi.state = nState;
  476.     lvi.pszText = (LPTSTR) lpszItem;
  477.     lvi.iImage = nImage;
  478.     lvi.lParam = lParam;
  479.     return (BOOL) ::SendMessage(m_hWnd, LVM_SETITEM, 0, (LPARAM)&lvi);
  480. }
  481.  
  482. BOOL CListCtrl::SetItemState(int nItem, UINT nState, UINT nStateMask)
  483. {
  484.     ASSERT(::IsWindow(m_hWnd));
  485.     LVITEM lvi;
  486.     lvi.stateMask = nStateMask;
  487.     lvi.state = nState;
  488.     return (BOOL) ::SendMessage(m_hWnd, LVM_SETITEMSTATE, nItem, (LPARAM)&lvi);
  489. }
  490.  
  491. BOOL CListCtrl::SetItemText(int nItem, int nSubItem, LPCTSTR lpszText)
  492. {
  493.     ASSERT(::IsWindow(m_hWnd));
  494.     ASSERT((GetStyle() & LVS_OWNERDATA)==0);
  495.     LVITEM lvi;
  496.     lvi.iSubItem = nSubItem;
  497.     lvi.pszText = (LPTSTR) lpszText;
  498.     return (BOOL) ::SendMessage(m_hWnd, LVM_SETITEMTEXT, nItem, (LPARAM)&lvi);
  499. }
  500.  
  501. CString CListCtrl::GetItemText(int nItem, int nSubItem) const
  502. {
  503.     ASSERT(::IsWindow(m_hWnd));
  504.     LVITEM lvi;
  505.     memset(&lvi, 0, sizeof(LVITEM));
  506.     lvi.iSubItem = nSubItem;
  507.     CString str;
  508.     int nLen = 128;
  509.     int nRes;
  510.     do
  511.     {
  512.         nLen *= 2;
  513.         lvi.cchTextMax = nLen;
  514.         lvi.pszText = str.GetBufferSetLength(nLen);
  515.         nRes  = (int)::SendMessage(m_hWnd, LVM_GETITEMTEXT, (WPARAM)nItem,
  516.             (LPARAM)&lvi);
  517.     } while (nRes == nLen-1);
  518.     str.ReleaseBuffer();
  519.     return str;
  520. }
  521.  
  522. int CListCtrl::GetItemText(int nItem, int nSubItem, LPTSTR lpszText, int nLen) const
  523. {
  524.     ASSERT(::IsWindow(m_hWnd));
  525.     LVITEM lvi;
  526.     memset(&lvi, 0, sizeof(LVITEM));
  527.     lvi.iSubItem = nSubItem;
  528.     lvi.cchTextMax = nLen;
  529.     lvi.pszText = lpszText;
  530.     return (int)::SendMessage(m_hWnd, LVM_GETITEMTEXT, (WPARAM)nItem,
  531.         (LPARAM)&lvi);
  532. }
  533.  
  534. DWORD CListCtrl::GetItemData(int nItem) const
  535. {
  536.     ASSERT(::IsWindow(m_hWnd));
  537.     LVITEM lvi;
  538.     memset(&lvi, 0, sizeof(LVITEM));
  539.     lvi.iItem = nItem;
  540.     lvi.mask = LVIF_PARAM;
  541.     VERIFY(::SendMessage(m_hWnd, LVM_GETITEM, 0, (LPARAM)&lvi));
  542.     return (DWORD)lvi.lParam;
  543. }
  544.  
  545. void CListCtrl::DrawItem(LPDRAWITEMSTRUCT)
  546. {
  547.     ASSERT(FALSE);
  548. }
  549.  
  550. BOOL CListCtrl::OnChildNotify(UINT message, WPARAM wParam, LPARAM lParam,
  551.     LRESULT* pResult)
  552. {
  553.     if (message != WM_DRAWITEM)
  554.         return CWnd::OnChildNotify(message, wParam, lParam, pResult);
  555.  
  556.     ASSERT(pResult == NULL);       // no return value expected
  557.     UNUSED(pResult); // unused in release builds
  558.  
  559.     DrawItem((LPDRAWITEMSTRUCT)lParam);
  560.     return TRUE;
  561. }
  562.  
  563. void CListCtrl::RemoveImageList(int nImageList)
  564. {
  565.     HIMAGELIST h = (HIMAGELIST)SendMessage(LVM_GETIMAGELIST,
  566.         (WPARAM)nImageList);
  567.     if (CImageList::FromHandlePermanent(h) != NULL)
  568.         SendMessage(LVM_SETIMAGELIST, (WPARAM)nImageList, NULL);
  569. }
  570.  
  571. void CListCtrl::OnNcDestroy()
  572. {
  573.     RemoveImageList(LVSIL_NORMAL);
  574.     RemoveImageList(LVSIL_SMALL);
  575.     RemoveImageList(LVSIL_STATE);
  576.  
  577.     CWnd::OnNcDestroy();
  578. }
  579.  
  580. CImageList* CListCtrl::CreateDragImage(int nItem, LPPOINT lpPoint)
  581. {
  582.     ASSERT(::IsWindow(m_hWnd));
  583.  
  584.     HIMAGELIST hImageList = (HIMAGELIST)::SendMessage(m_hWnd,
  585.         LVM_CREATEDRAGIMAGE, nItem, (LPARAM)lpPoint);
  586.     if (hImageList == NULL)
  587.         return NULL;
  588.  
  589.     CImageList* pImageList = new CImageList;
  590.     VERIFY(pImageList->Attach(hImageList));
  591.     return pImageList;
  592. }
  593.  
  594. /////////////////////////////////////////////////////////////////////////////
  595. // CTreeCtrl
  596.  
  597. BEGIN_MESSAGE_MAP(CTreeCtrl, CWnd)
  598.     //{{AFX_MSG_MAP(CTreeCtrl)
  599.     ON_WM_DESTROY()
  600.     //}}AFX_MSG_MAP
  601. END_MESSAGE_MAP()
  602.  
  603. BOOL CTreeCtrl::Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd,
  604.     UINT nID)
  605. {
  606.     // initialize common controls
  607.     VERIFY(AfxDeferRegisterClass(AFX_WNDCOMMCTL_TREEVIEW_REG));
  608.  
  609.     CWnd* pWnd = this;
  610.     return pWnd->Create(WC_TREEVIEW, NULL, dwStyle, rect, pParentWnd, nID);
  611. }
  612.  
  613. CTreeCtrl::~CTreeCtrl()
  614. {
  615.     DestroyWindow();
  616. }
  617.  
  618. BOOL CTreeCtrl::GetItemRect(HTREEITEM hItem, LPRECT lpRect, BOOL bTextOnly) const
  619. {
  620.     ASSERT(::IsWindow(m_hWnd));
  621.     *(HTREEITEM*)lpRect = hItem;
  622.     return (BOOL)::SendMessage(m_hWnd, TVM_GETITEMRECT, (WPARAM)bTextOnly,
  623.         (LPARAM)lpRect);
  624. }
  625.  
  626. CString CTreeCtrl::GetItemText(HTREEITEM hItem) const
  627. {
  628.     ASSERT(::IsWindow(m_hWnd));
  629.     TVITEM item;
  630.     item.hItem = hItem;
  631.     item.mask = TVIF_TEXT;
  632.     CString str;
  633.     int nLen = 128;
  634.     int nRes;
  635.     do
  636.     {
  637.         nLen *= 2;
  638.         item.pszText = str.GetBufferSetLength(nLen);
  639.         item.cchTextMax = nLen;
  640.         ::SendMessage(m_hWnd, TVM_GETITEM, 0, (LPARAM)&item);
  641.         nRes = lstrlen(item.pszText);
  642.     } while (nRes == nLen-1);
  643.     str.ReleaseBuffer();
  644.     return str;
  645. }
  646.  
  647. BOOL CTreeCtrl::GetItemImage(HTREEITEM hItem, int& nImage, int& nSelectedImage) const
  648. {
  649.     ASSERT(::IsWindow(m_hWnd));
  650.     TVITEM item;
  651.     item.hItem = hItem;
  652.     item.mask = TVIF_IMAGE|TVIF_SELECTEDIMAGE;
  653.     BOOL bRes = (BOOL)::SendMessage(m_hWnd, TVM_GETITEM, 0, (LPARAM)&item);
  654.     if (bRes)
  655.     {
  656.         nImage = item.iImage;
  657.         nSelectedImage = item.iSelectedImage;
  658.     }
  659.     return bRes;
  660. }
  661.  
  662. UINT CTreeCtrl::GetItemState(HTREEITEM hItem, UINT nStateMask) const
  663. {
  664.     ASSERT(::IsWindow(m_hWnd));
  665.     TVITEM item;
  666.     item.hItem = hItem;
  667.     item.mask = TVIF_STATE;
  668.     item.stateMask = nStateMask;
  669.     item.state = 0;
  670.     VERIFY(::SendMessage(m_hWnd, TVM_GETITEM, 0, (LPARAM)&item));
  671.     return item.state;
  672. }
  673.  
  674. DWORD CTreeCtrl::GetItemData(HTREEITEM hItem) const
  675. {
  676.     ASSERT(::IsWindow(m_hWnd));
  677.     TVITEM item;
  678.     item.hItem = hItem;
  679.     item.mask = TVIF_PARAM;
  680.     VERIFY(::SendMessage(m_hWnd, TVM_GETITEM, 0, (LPARAM)&item));
  681.     return (DWORD)item.lParam;
  682. }
  683.  
  684. BOOL CTreeCtrl::ItemHasChildren(HTREEITEM hItem) const
  685. {
  686.     ASSERT(::IsWindow(m_hWnd));
  687.     TVITEM item;
  688.     item.hItem = hItem;
  689.     item.mask = TVIF_CHILDREN;
  690.     ::SendMessage(m_hWnd, TVM_GETITEM, 0, (LPARAM)&item);
  691.     return item.cChildren;
  692. }
  693.  
  694. BOOL CTreeCtrl::SetItem(HTREEITEM hItem, UINT nMask, LPCTSTR lpszItem, int nImage,
  695.     int nSelectedImage, UINT nState, UINT nStateMask, LPARAM lParam)
  696. {
  697.     ASSERT(::IsWindow(m_hWnd));
  698.     TVITEM item;
  699.     item.hItem = hItem;
  700.     item.mask = nMask;
  701.     item.pszText = (LPTSTR) lpszItem;
  702.     item.iImage = nImage;
  703.     item.iSelectedImage = nSelectedImage;
  704.     item.state = nState;
  705.     item.stateMask = nStateMask;
  706.     item.lParam = lParam;
  707.     return (BOOL)::SendMessage(m_hWnd, TVM_SETITEM, 0, (LPARAM)&item);
  708. }
  709.  
  710. HTREEITEM CTreeCtrl::InsertItem(UINT nMask, LPCTSTR lpszItem, int nImage,
  711.     int nSelectedImage, UINT nState, UINT nStateMask, LPARAM lParam,
  712.     HTREEITEM hParent, HTREEITEM hInsertAfter)
  713. {
  714.     ASSERT(::IsWindow(m_hWnd));
  715.     TVINSERTSTRUCT tvis;
  716.     tvis.hParent = hParent;
  717.     tvis.hInsertAfter = hInsertAfter;
  718.     tvis.item.mask = nMask;
  719.     tvis.item.pszText = (LPTSTR) lpszItem;
  720.     tvis.item.iImage = nImage;
  721.     tvis.item.iSelectedImage = nSelectedImage;
  722.     tvis.item.state = nState;
  723.     tvis.item.stateMask = nStateMask;
  724.     tvis.item.lParam = lParam;
  725.     return (HTREEITEM)::SendMessage(m_hWnd, TVM_INSERTITEM, 0, (LPARAM)&tvis);
  726. }
  727.  
  728. HTREEITEM CTreeCtrl::HitTest(CPoint pt, UINT* pFlags) const
  729. {
  730.     ASSERT(::IsWindow(m_hWnd));
  731.     TVHITTESTINFO hti;
  732.     hti.pt = pt;
  733.     HTREEITEM h = (HTREEITEM)::SendMessage(m_hWnd, TVM_HITTEST, 0,
  734.         (LPARAM)&hti);
  735.     if (pFlags != NULL)
  736.         *pFlags = hti.flags;
  737.     return h;
  738. }
  739.  
  740. void CTreeCtrl::RemoveImageList(int nImageList)
  741. {
  742.     HIMAGELIST h = (HIMAGELIST)SendMessage(TVM_GETIMAGELIST,
  743.         (WPARAM)nImageList);
  744.     if (CImageList::FromHandlePermanent(h) != NULL)
  745.         SendMessage(TVM_SETIMAGELIST, (WPARAM)nImageList, NULL);
  746. }
  747.  
  748. void CTreeCtrl::OnDestroy()
  749. {
  750.     RemoveImageList(LVSIL_NORMAL);
  751.     RemoveImageList(LVSIL_STATE);
  752.  
  753.     CWnd::OnDestroy();
  754. }
  755.  
  756. CImageList* CTreeCtrl::CreateDragImage(HTREEITEM hItem)
  757. {
  758.     ASSERT(::IsWindow(m_hWnd));
  759.  
  760.     HIMAGELIST hImageList = (HIMAGELIST)::SendMessage(m_hWnd,
  761.         TVM_CREATEDRAGIMAGE, 0, (LPARAM)hItem);
  762.     if (hImageList == NULL)
  763.         return NULL;
  764.  
  765.     CImageList* pImageList = new CImageList;
  766.     VERIFY(pImageList->Attach(hImageList));
  767.     return pImageList;
  768. }
  769.  
  770. BOOL CTreeCtrl::GetCheck(HTREEITEM hItem) const
  771. {
  772.     ASSERT(::IsWindow(m_hWnd));
  773.     TVITEM item;
  774.     item.mask = TVIF_HANDLE | TVIF_STATE;
  775.     item.hItem = hItem;
  776.     item.stateMask = TVIS_STATEIMAGEMASK;
  777.     VERIFY(::SendMessage(m_hWnd, TVM_GETITEM, 0, (LPARAM)&item));
  778.     // Return zero if it's not checked, or nonzero otherwise.
  779.     return ((BOOL)(item.state >> 12) -1);
  780. }
  781.  
  782. BOOL CTreeCtrl::SetCheck(HTREEITEM hItem, BOOL fCheck)
  783. {
  784.     ASSERT(::IsWindow(m_hWnd));
  785.     TVITEM item;
  786.     item.mask = TVIF_HANDLE | TVIF_STATE;
  787.     item.hItem = hItem;
  788.     item.stateMask = TVIS_STATEIMAGEMASK;
  789.  
  790.     /*
  791.     Since state images are one-based, 1 in this macro turns the check off, and
  792.     2 turns it on.
  793.     */
  794.     item.state = INDEXTOSTATEIMAGEMASK((fCheck ? 2 : 1));
  795.  
  796.     return (BOOL)::SendMessage(m_hWnd, TVM_SETITEM, 0, (LPARAM)&item);
  797. }
  798.  
  799. /////////////////////////////////////////////////////////////////////////////
  800. // CSpinButtonCtrl
  801.  
  802. BOOL CSpinButtonCtrl::Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd,
  803.     UINT nID)
  804. {
  805.     // initialize common controls
  806.     VERIFY(AfxDeferRegisterClass(AFX_WNDCOMMCTL_UPDOWN_REG));
  807.  
  808.     CWnd* pWnd = this;
  809.     return pWnd->Create(UPDOWN_CLASS, NULL, dwStyle, rect, pParentWnd, nID);
  810. }
  811.  
  812. CSpinButtonCtrl::~CSpinButtonCtrl()
  813. {
  814.     DestroyWindow();
  815. }
  816.  
  817. void CSpinButtonCtrl::GetRange(int &lower, int& upper) const
  818. {
  819.     ASSERT(::IsWindow(m_hWnd));
  820.     DWORD dw = ::SendMessage(m_hWnd, UDM_GETRANGE, 0, 0l);
  821.     lower = (int)(short)HIWORD(dw);
  822.     upper = (int)(short)LOWORD(dw);
  823. }
  824.  
  825. /////////////////////////////////////////////////////////////////////////////
  826. // CSliderCtrl
  827.  
  828. BOOL CSliderCtrl::Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd,
  829.     UINT nID)
  830. {
  831.     // initialize common controls
  832.     VERIFY(AfxDeferRegisterClass(AFX_WNDCOMMCTL_BAR_REG));
  833.  
  834.     CWnd* pWnd = this;
  835.     return pWnd->Create(TRACKBAR_CLASS, NULL, dwStyle, rect, pParentWnd, nID);
  836. }
  837.  
  838. CSliderCtrl::~CSliderCtrl()
  839. {
  840.     DestroyWindow();
  841. }
  842.  
  843. void CSliderCtrl::GetRange(int& nMin, int& nMax) const
  844. {
  845.     ASSERT(::IsWindow(m_hWnd));
  846.     nMin = GetRangeMin();
  847.     nMax = GetRangeMax();
  848. }
  849.  
  850. void CSliderCtrl::SetRange(int nMin, int nMax, BOOL bRedraw)
  851. {
  852.     SetRangeMin(nMin, bRedraw);
  853.     SetRangeMax(nMax, bRedraw);
  854. }
  855.  
  856. void CSliderCtrl::GetSelection(int& nMin, int& nMax) const
  857. {
  858.     ASSERT(::IsWindow(m_hWnd));
  859.     nMin = ::SendMessage(m_hWnd, TBM_GETSELSTART, 0, 0L);
  860.     nMax = ::SendMessage(m_hWnd, TBM_GETSELEND, 0, 0L);
  861. }
  862.  
  863. void CSliderCtrl::SetSelection(int nMin, int nMax)
  864. {
  865.     ASSERT(::IsWindow(m_hWnd));
  866.     ::SendMessage(m_hWnd, TBM_SETSELSTART, 0, (LPARAM)nMin);
  867.     ::SendMessage(m_hWnd, TBM_SETSELEND, 0, (LPARAM)nMax);
  868. }
  869.  
  870. /////////////////////////////////////////////////////////////////////////////
  871. // CProgressCtrl
  872.  
  873. BOOL CProgressCtrl::Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd,
  874.     UINT nID)
  875. {
  876.     // initialize common controls
  877.     VERIFY(AfxDeferRegisterClass(AFX_WNDCOMMCTL_PROGRESS_REG));
  878.  
  879.     CWnd* pWnd = this;
  880.     return pWnd->Create(PROGRESS_CLASS, NULL, dwStyle, rect, pParentWnd, nID);
  881. }
  882.  
  883. CProgressCtrl::~CProgressCtrl()
  884. {
  885.     DestroyWindow();
  886. }
  887.  
  888. /////////////////////////////////////////////////////////////////////////////
  889. // CHeaderCtrl
  890.  
  891. BOOL CHeaderCtrl::Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd,
  892.     UINT nID)
  893. {
  894.     // initialize common controls
  895.     VERIFY(AfxDeferRegisterClass(AFX_WNDCOMMCTL_LISTVIEW_REG));
  896.  
  897.     CWnd* pWnd = this;
  898.     return pWnd->Create(WC_HEADER, NULL, dwStyle, rect, pParentWnd, nID);
  899. }
  900.  
  901. CHeaderCtrl::~CHeaderCtrl()
  902. {
  903.     DestroyWindow();
  904. }
  905.  
  906. void CHeaderCtrl::DrawItem(LPDRAWITEMSTRUCT)
  907. {
  908.     ASSERT(FALSE);  // must override for self draw header controls
  909. }
  910.  
  911. BOOL CHeaderCtrl::OnChildNotify(UINT message, WPARAM wParam, LPARAM lParam,
  912.     LRESULT* pResult)
  913. {
  914.     if (message != WM_DRAWITEM)
  915.         return CWnd::OnChildNotify(message, wParam, lParam, pResult);
  916.  
  917.     ASSERT(pResult == NULL);       // no return value expected
  918.     UNUSED(pResult); // unused in release builds
  919.  
  920.     DrawItem((LPDRAWITEMSTRUCT)lParam);
  921.     return TRUE;
  922. }
  923.  
  924. /////////////////////////////////////////////////////////////////////////////
  925. // CHotKeyCtrl
  926.  
  927. BOOL CHotKeyCtrl::Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd,
  928.     UINT nID)
  929. {
  930.     // initialize common controls
  931.     VERIFY(AfxDeferRegisterClass(AFX_WNDCOMMCTL_HOTKEY_REG));
  932.  
  933.     CWnd* pWnd = this;
  934.     return pWnd->Create(HOTKEY_CLASS, NULL, dwStyle, rect, pParentWnd, nID);
  935. }
  936.  
  937. CHotKeyCtrl::~CHotKeyCtrl()
  938. {
  939.     DestroyWindow();
  940. }
  941.  
  942. void CHotKeyCtrl::GetHotKey(WORD &wVirtualKeyCode, WORD &wModifiers) const
  943. {
  944.     ASSERT(::IsWindow(m_hWnd));
  945.     DWORD dw = ::SendMessage(m_hWnd, HKM_GETHOTKEY, 0, 0L);
  946.     wVirtualKeyCode = LOBYTE(LOWORD(dw));
  947.     wModifiers = HIBYTE(LOWORD(dw));
  948. }
  949.  
  950. /////////////////////////////////////////////////////////////////////////////
  951. // CTabCtrl
  952.  
  953. BEGIN_MESSAGE_MAP(CTabCtrl, CWnd)
  954.     //{{AFX_MSG_MAP(CTabCtrl)
  955.     ON_WM_DESTROY()
  956.     //}}AFX_MSG_MAP
  957. END_MESSAGE_MAP()
  958.  
  959. BOOL CTabCtrl::Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd,
  960.     UINT nID)
  961. {
  962.     // initialize common controls
  963.     VERIFY(AfxDeferRegisterClass(AFX_WNDCOMMCTL_TAB_REG));
  964.  
  965.     CWnd* pWnd = this;
  966.     return pWnd->Create(WC_TABCONTROL, NULL, dwStyle, rect, pParentWnd, nID);
  967. }
  968.  
  969. CTabCtrl::~CTabCtrl()
  970. {
  971.     DestroyWindow();
  972. }
  973.  
  974. void CTabCtrl::DrawItem(LPDRAWITEMSTRUCT)
  975. {
  976.     ASSERT(FALSE);  // must override for self draw tab controls
  977. }
  978.  
  979. BOOL CTabCtrl::OnChildNotify(UINT message, WPARAM wParam, LPARAM lParam,
  980.     LRESULT* pResult)
  981. {
  982.     if (message != WM_DRAWITEM)
  983.         return CWnd::OnChildNotify(message, wParam, lParam, pResult);
  984.  
  985.     ASSERT(pResult == NULL);       // no return value expected
  986.     UNUSED(pResult); // unused in release builds
  987.  
  988.     DrawItem((LPDRAWITEMSTRUCT)lParam);
  989.     return TRUE;
  990. }
  991.  
  992. void CTabCtrl::OnDestroy()
  993. {
  994.     HIMAGELIST h = (HIMAGELIST)SendMessage(TCM_GETIMAGELIST);
  995.     if (CImageList::FromHandlePermanent(h) != NULL)
  996.         SendMessage(TCM_SETIMAGELIST, NULL, NULL);
  997.  
  998.     CWnd::OnDestroy();
  999. }
  1000.  
  1001. DWORD CTabCtrl::GetItemState(int nItem, DWORD dwMask) const
  1002. {
  1003.     ASSERT(::IsWindow(m_hWnd));
  1004.  
  1005.     TCITEM item;
  1006.     item.mask = TCIF_STATE;
  1007.     item.dwStateMask = dwMask;
  1008.     VERIFY(::SendMessage(m_hWnd, TCM_GETITEM, (WPARAM)nItem, (LPARAM)&item));
  1009.  
  1010.     return item.dwState;
  1011. }
  1012.  
  1013. BOOL CTabCtrl::SetItemState(int nItem, DWORD dwMask, DWORD dwState)
  1014. {
  1015.     ASSERT(::IsWindow(m_hWnd));
  1016.  
  1017.     TCITEM item;
  1018.     item.mask = TCIF_STATE;
  1019.     item.dwState = dwState;
  1020.     item.dwStateMask = dwMask;
  1021.  
  1022.     return (BOOL) ::SendMessage(m_hWnd, TCM_SETITEM,
  1023.         (WPARAM) nItem, (LPARAM) &item);
  1024. }
  1025.  
  1026. BOOL CTabCtrl::InsertItem(UINT nMask, int nItem, LPCTSTR lpszItem,
  1027.     int nImage, LPARAM lParam)
  1028. {
  1029.     ASSERT(::IsWindow(m_hWnd));
  1030.  
  1031.     TCITEM item;
  1032.     item.mask = nMask;
  1033.     item.iImage = nImage;
  1034.     item.lParam = lParam;
  1035.     item.pszText = (LPTSTR) lpszItem;
  1036.  
  1037.     return (BOOL) ::SendMessage(m_hWnd, TCM_INSERTITEM, nItem, (LPARAM) &item);
  1038. }
  1039.  
  1040. BOOL CTabCtrl::InsertItem(UINT nMask, int nItem, LPCTSTR lpszItem,
  1041.     int nImage, LPARAM lParam, DWORD dwState, DWORD dwStateMask)
  1042. {
  1043.     ASSERT(::IsWindow(m_hWnd));
  1044.  
  1045.     TCITEM item;
  1046.     item.mask = nMask;
  1047.     item.iImage = nImage;
  1048.     item.lParam = lParam;
  1049.     item.pszText = (LPTSTR) lpszItem;
  1050.     item.dwState = dwState;
  1051.     item.dwStateMask = dwStateMask;
  1052.  
  1053.     return (BOOL) ::SendMessage(m_hWnd, TCM_INSERTITEM, nItem, (LPARAM) &item);
  1054. }
  1055.  
  1056.  
  1057. /////////////////////////////////////////////////////////////////////////////
  1058. // CAnimateCtrl
  1059.  
  1060. BOOL CAnimateCtrl::Create(DWORD dwStyle, const RECT& rect,
  1061.     CWnd* pParentWnd, UINT nID)
  1062. {
  1063.     // initialize common controls
  1064.     VERIFY(AfxDeferRegisterClass(AFX_WNDCOMMCTL_ANIMATE_REG));
  1065.  
  1066.     CWnd* pWnd = this;
  1067.     return pWnd->Create(ANIMATE_CLASS, NULL, dwStyle, rect, pParentWnd, nID);
  1068. }
  1069.  
  1070. CAnimateCtrl::~CAnimateCtrl()
  1071. {
  1072.     DestroyWindow();
  1073. }
  1074.  
  1075. #ifndef _AFX_NO_RICHEDIT_SUPPORT
  1076.  
  1077. /////////////////////////////////////////////////////////////////////////////
  1078. // CRichEdit
  1079.  
  1080. CRichEditCtrl::~CRichEditCtrl()
  1081. {
  1082.     DestroyWindow();
  1083. }
  1084.  
  1085. #endif //!_AFX_NO_RICHEDIT_SUPPORT
  1086.  
  1087. /////////////////////////////////////////////////////////////////////////////
  1088. // CImageList
  1089.  
  1090. #include "fixalloc.h"
  1091.  
  1092. class CTempImageList : public CImageList
  1093. {
  1094.     DECLARE_DYNCREATE(CTempImageList)
  1095.     DECLARE_FIXED_ALLOC(CTempImageList);
  1096. };
  1097.  
  1098. CHandleMap* PASCAL afxMapHIMAGELIST(BOOL bCreate)
  1099. {
  1100.     AFX_MODULE_THREAD_STATE* pState = AfxGetModuleThreadState();
  1101.     if (pState->m_pmapHIMAGELIST == NULL && bCreate)
  1102.     {
  1103.         BOOL bEnable = AfxEnableMemoryTracking(FALSE);
  1104. #ifndef _AFX_PORTABLE
  1105.         _PNH pnhOldHandler = AfxSetNewHandler(&AfxCriticalNewHandler);
  1106. #endif
  1107.         pState->m_pmapHIMAGELIST = new CHandleMap(RUNTIME_CLASS(CTempImageList),
  1108.             offsetof(CImageList, m_hImageList));
  1109.  
  1110. #ifndef _AFX_PORTABLE
  1111.         AfxSetNewHandler(pnhOldHandler);
  1112. #endif
  1113.         AfxEnableMemoryTracking(bEnable);
  1114.     }
  1115.     return pState->m_pmapHIMAGELIST;
  1116. }
  1117.  
  1118. CImageList::CImageList()
  1119. {
  1120.     m_hImageList = NULL;
  1121. }
  1122.  
  1123. CImageList::~CImageList()
  1124. {
  1125.     DeleteImageList();
  1126. }
  1127.  
  1128. HIMAGELIST CImageList::Detach()
  1129. {
  1130.     HIMAGELIST hImageList = m_hImageList;
  1131.     if (hImageList != NULL)
  1132.     {
  1133.         CHandleMap* pMap = afxMapHIMAGELIST();
  1134.         if (pMap != NULL)
  1135.             pMap->RemoveHandle(m_hImageList);
  1136.     }
  1137.  
  1138.     m_hImageList = NULL;
  1139.     return hImageList;
  1140. }
  1141.  
  1142. BOOL CImageList::DeleteImageList()
  1143. {
  1144.     if (m_hImageList == NULL)
  1145.         return FALSE;
  1146.     return ImageList_Destroy(Detach());
  1147. }
  1148.  
  1149. CImageList* PASCAL CImageList::FromHandle(HIMAGELIST h)
  1150. {
  1151.     CHandleMap* pMap = afxMapHIMAGELIST(TRUE);
  1152.     ASSERT(pMap != NULL);
  1153.     CImageList* pImageList = (CImageList*)pMap->FromHandle(h);
  1154.     ASSERT(pImageList == NULL || pImageList->m_hImageList == h);
  1155.     return pImageList;
  1156. }
  1157.  
  1158. CImageList* PASCAL CImageList::FromHandlePermanent(HIMAGELIST h)
  1159. {
  1160.     CHandleMap* pMap = afxMapHIMAGELIST();
  1161.     CImageList* pImageList = NULL;
  1162.     if (pMap != NULL)
  1163.     {
  1164.         // only look in the permanent map - does no allocations
  1165.         pImageList = (CImageList*)pMap->LookupPermanent(h);
  1166.         ASSERT(pImageList == NULL || pImageList->m_hImageList == h);
  1167.     }
  1168.     return pImageList;
  1169. }
  1170.  
  1171. BOOL CImageList::Create(int cx, int cy, UINT nFlags, int nInitial, int nGrow)
  1172. {
  1173.     return Attach(ImageList_Create(cx, cy, nFlags, nInitial, nGrow));
  1174. }
  1175.  
  1176. BOOL CImageList::Create(UINT nBitmapID, int cx, int nGrow, COLORREF crMask)
  1177. {
  1178.     ASSERT(HIWORD(nBitmapID) == 0);
  1179.     HINSTANCE hInst = AfxFindResourceHandle((LPCTSTR)nBitmapID, RT_BITMAP);
  1180.     ASSERT(hInst != NULL);
  1181.     return Attach(ImageList_LoadBitmap(hInst,
  1182.         (LPCTSTR)nBitmapID, cx, nGrow, crMask));
  1183. }
  1184.  
  1185. BOOL CImageList::Create(LPCTSTR lpszBitmapID, int cx, int nGrow,
  1186.     COLORREF crMask)
  1187. {
  1188.     HINSTANCE hInst = AfxFindResourceHandle(lpszBitmapID, RT_BITMAP);
  1189.     ASSERT(hInst != NULL);
  1190.     return Attach(ImageList_LoadBitmap(hInst, lpszBitmapID, cx, nGrow, crMask));
  1191. }
  1192.  
  1193. BOOL CImageList::Create(CImageList& imagelist1, int nImage1,
  1194.     CImageList& imagelist2, int nImage2, int dx, int dy)
  1195. {
  1196.     return Attach(ImageList_Merge(imagelist1.m_hImageList, nImage1,
  1197.         imagelist2.m_hImageList, nImage2, dx, dy));
  1198. }
  1199.  
  1200. BOOL CImageList::Attach(HIMAGELIST hImageList)
  1201. {
  1202.     ASSERT(m_hImageList == NULL);      // only attach once, detach on destroy
  1203.     ASSERT(FromHandlePermanent(hImageList) == NULL);
  1204.  
  1205.     if (hImageList == NULL)
  1206.         return FALSE;
  1207.  
  1208.     CHandleMap* pMap = afxMapHIMAGELIST(TRUE);
  1209.     ASSERT(pMap != NULL);
  1210.  
  1211.     pMap->SetPermanent(m_hImageList = hImageList, this);
  1212.     return TRUE;
  1213. }
  1214.  
  1215. #ifndef _AFX_NO_OLE_SUPPORT
  1216. BOOL CImageList::Read(CArchive* pArchive)
  1217. {
  1218.     ASSERT(m_hImageList == NULL);
  1219.     ASSERT(pArchive != NULL);
  1220.     ASSERT(pArchive->IsLoading());
  1221.     CArchiveStream arcstream(pArchive);
  1222.  
  1223.     m_hImageList = ImageList_Read(&arcstream);
  1224.     return (m_hImageList != NULL);
  1225. }
  1226.  
  1227. BOOL CImageList::Write(CArchive* pArchive)
  1228. {
  1229.     ASSERT(m_hImageList != NULL);
  1230.     ASSERT(pArchive != NULL);
  1231.     ASSERT(pArchive->IsStoring());
  1232.     CArchiveStream arcstream(pArchive);
  1233.     return ImageList_Write(m_hImageList, &arcstream);
  1234. }
  1235. #endif //_AFX_NO_OLE_SUPPORT
  1236.  
  1237. #ifdef _DEBUG
  1238. void CImageList::Dump(CDumpContext& dc) const
  1239. {
  1240.     CObject::Dump(dc);
  1241.  
  1242.     dc << "m_hImageList = " << (UINT)m_hImageList;
  1243.     dc << "\n";
  1244. }
  1245.  
  1246. void CImageList::AssertValid() const
  1247. {
  1248.     CObject::AssertValid();
  1249.     if (m_hImageList == NULL)
  1250.         return;
  1251.     // should also be in the permanent or temporary handle map
  1252.     CObject* p;
  1253.  
  1254.     CHandleMap* pMap = afxMapHIMAGELIST();
  1255.     ASSERT(pMap != NULL);
  1256.  
  1257.     ASSERT((p = pMap->LookupPermanent(m_hImageList)) != NULL ||
  1258.         (p = pMap->LookupTemporary(m_hImageList)) != NULL);
  1259.     ASSERT((CImageList*)p == this);   // must be us
  1260. }
  1261. #endif
  1262.  
  1263.  
  1264. /////////////////////////////////////////////////////////////////////////////
  1265.  
  1266. #ifdef AFX_CMNCTL_SEG
  1267. #pragma code_seg(AFX_CMNCTL_SEG)
  1268. #endif
  1269.  
  1270. #ifndef _AFX_ENABLE_INLINES
  1271.  
  1272. static const char _szAfxWinInl[] = "afxcmn.inl";
  1273. #undef THIS_FILE
  1274. #define THIS_FILE _szAfxWinInl
  1275. #define _AFXCMN_INLINE
  1276. #include "afxcmn.inl"
  1277.  
  1278. #endif //_AFX_ENABLE_INLINES
  1279.  
  1280. /////////////////////////////////////////////////////////////////////////////
  1281.  
  1282. #ifdef AFX_INIT_SEG
  1283. #pragma code_seg(AFX_INIT_SEG)
  1284. #endif
  1285.  
  1286. IMPLEMENT_DYNAMIC(CDragListBox, CListBox)
  1287. IMPLEMENT_DYNAMIC(CSpinButtonCtrl, CWnd)
  1288. IMPLEMENT_DYNAMIC(CSliderCtrl, CWnd)
  1289. IMPLEMENT_DYNAMIC(CProgressCtrl, CWnd)
  1290. IMPLEMENT_DYNAMIC(CComboBoxEx, CComboBox)
  1291. IMPLEMENT_DYNAMIC(CHeaderCtrl, CWnd)
  1292. IMPLEMENT_DYNAMIC(CHotKeyCtrl, CWnd)
  1293. IMPLEMENT_DYNAMIC(CAnimateCtrl, CWnd)
  1294. IMPLEMENT_DYNAMIC(CTabCtrl, CWnd)
  1295. IMPLEMENT_DYNAMIC(CTreeCtrl, CWnd)
  1296. IMPLEMENT_DYNAMIC(CListCtrl, CWnd)
  1297. IMPLEMENT_DYNAMIC(CToolBarCtrl, CWnd)
  1298. IMPLEMENT_DYNAMIC(CStatusBarCtrl, CWnd)
  1299. IMPLEMENT_DYNCREATE(CImageList, CObject)
  1300.  
  1301. IMPLEMENT_DYNCREATE(CTempImageList, CImageList);
  1302.  
  1303. #ifndef _AFX_NO_RICHEDIT_SUPPORT
  1304. IMPLEMENT_DYNAMIC(CRichEditCtrl, CWnd)
  1305. #endif
  1306.  
  1307. #pragma warning(disable: 4074)
  1308. #pragma init_seg(compiler)
  1309. IMPLEMENT_FIXED_ALLOC(CTempImageList, 64);
  1310.  
  1311. /////////////////////////////////////////////////////////////////////////////
  1312.