home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / mfc / controls / xlist / xlistctl.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1998-03-27  |  34.8 KB  |  1,405 lines

  1. // xlistctl.cpp : Implementation of the CXlistCtrl OLE control class.
  2. //
  3. // This is a part of the Microsoft Foundation Classes C++ library.
  4. // Copyright (C) 1992-1998 Microsoft Corporation
  5. // All rights reserved.
  6. //
  7. // This source code is only intended as a supplement to the
  8. // Microsoft Foundation Classes Reference and related
  9. // electronic documentation provided with the library.
  10. // See these sources for detailed information regarding the
  11. // Microsoft Foundation Classes product.
  12.  
  13. #include "stdafx.h"
  14. #include "xlist.h"
  15. #include "xlistctl.h"
  16. #include "xlistppg.h"
  17.  
  18. #ifdef _DEBUG
  19. #undef THIS_FILE
  20. static char BASED_CODE THIS_FILE[] = __FILE__;
  21. #endif
  22.  
  23.  
  24. /////////////////////////////////////////////////////////////////////////////
  25. // Numeric constants
  26.  
  27. const int ITEMSPACING       =   4;
  28. const int MAXTEXTLEN        = 128;
  29.  
  30.  
  31. /////////////////////////////////////////////////////////////////////////////
  32. // Forward declarations
  33.  
  34. short GetFontHeight(LPFONTDISP lpfd);
  35. long GetPictureHeight(LPPICTUREDISP lppd);
  36. long GetPictureWidth(LPPICTUREDISP lppd);
  37. void GetProperty(LPDISPATCH lpd, short dispId, short propType, void *value);
  38. STDAPI_(int) XformWidthInHimetricToPixels(HDC hDC, int iWidthInHiMetric);
  39. STDAPI_(int) XformHeightInHimetricToPixels(HDC hDC, int iHeightInHiMetric);
  40.  
  41. #define HIMETRIC_PER_INCH   2540      // number HIMETRIC units per inch
  42. #define MAP_LOGHIM_TO_PIX(x,ppli)   MulDiv((ppli), (x), HIMETRIC_PER_INCH)
  43.  
  44.  
  45. /////////////////////////////////////////////////////////////////////////////
  46. // CItemData::CItemData - Constructor
  47.  
  48. CItemData::CItemData(const TCHAR *pstrText, LPFONTDISP lpFontDisp, LPPICTUREDISP lpPicDisp)
  49. {
  50.     pBack = NULL;
  51.     pFore = NULL;
  52.  
  53.     // Init text
  54.     if (pstrText)
  55.         pText = new CString(pstrText);
  56.     else
  57.         pText = NULL;
  58.  
  59.     // Init picture holder
  60.     if (lpPicDisp)
  61.     {
  62.        pPicHolder = new CPictureHolder;
  63.        pPicHolder->SetPictureDispatch(lpPicDisp);
  64.     }
  65.     else pPicHolder = NULL;
  66.  
  67.     // Init font holder
  68.     if (lpFontDisp)
  69.     {
  70.        pFontHolder = new CFontHolder(NULL);
  71.        pFontHolder->InitializeFont(NULL, lpFontDisp);
  72.     }
  73.     else pFontHolder = NULL;
  74. }
  75.  
  76.  
  77. /////////////////////////////////////////////////////////////////////////////
  78. // CItemData::CItemData - Destructor
  79.  
  80. CItemData::~CItemData()
  81. {
  82.     if (pBack) delete pBack;
  83.     if (pFore) delete pFore;
  84.     if (pText) delete pText;
  85.     if (pFontHolder) delete pFontHolder;
  86.     if (pPicHolder) delete pPicHolder;
  87. }
  88.  
  89. /////////////////////////////////////////////////////////////////////////////
  90. // CItemData::GetBackColor - Return the item's background color.
  91.  
  92. OLE_COLOR *CItemData::GetBackColor()
  93. {
  94.     return pBack;
  95. }
  96.  
  97.  
  98. /////////////////////////////////////////////////////////////////////////////
  99. // CItemData::SetBackColor - Set the item's background color.
  100.  
  101. void CItemData::SetBackColor(OLE_COLOR *pNewBack)
  102. {
  103.     if (pNewBack)
  104.     {
  105.         if (!pBack)
  106.         {
  107.             pBack = new OLE_COLOR;
  108.         }
  109.         *pBack = *pNewBack;
  110.     }
  111.     else
  112.         if (pBack)
  113.         {
  114.             delete pBack;
  115.             pBack = NULL;
  116.         }
  117. }
  118.  
  119.  
  120. /////////////////////////////////////////////////////////////////////////////
  121. // CItemData::GetForeColor - Return the item's foreground color.
  122.  
  123. OLE_COLOR *CItemData::GetForeColor()
  124. {
  125.     return pFore;
  126. }
  127.  
  128.  
  129. /////////////////////////////////////////////////////////////////////////////
  130. // CItemData::SetForeColor - Set the item's foreground color.
  131.  
  132. void CItemData::SetForeColor(OLE_COLOR *pNewFore)
  133. {
  134.     if (pNewFore)
  135.     {
  136.         if (!pFore)
  137.         {
  138.             pFore = new OLE_COLOR;
  139.         }
  140.         *pFore = *pNewFore;
  141.     }
  142.     else
  143.         if (pFore)
  144.         {
  145.             delete pFore;
  146.             pFore = NULL;
  147.         }
  148. }
  149.  
  150.  
  151. /////////////////////////////////////////////////////////////////////////////
  152. // CItemData::GetText - Return the item's text.
  153.  
  154. void CItemData::GetText(LPTSTR buffer, short szBuffer)
  155. {
  156.     if (pText)
  157.     {
  158.         _tcsncpy(buffer, pText->GetBuffer(szBuffer), szBuffer);
  159.         pText->ReleaseBuffer();
  160.     }
  161.     else
  162.         _tcscpy(buffer, _T(""));
  163. }
  164.  
  165.  
  166. /////////////////////////////////////////////////////////////////////////////
  167. // CItemData::SetText - Set the item's text.
  168.  
  169. void CItemData::SetText(const TCHAR *pstrText)
  170. {
  171.     if (_tcslen(pstrText) > 0)
  172.     {
  173.         if (!pText)
  174.         {
  175.             pText = new CString(pstrText);
  176.         }
  177.         else *pText = pstrText;
  178.     }
  179.     else
  180.         if (pText)
  181.         {
  182.             delete pText;
  183.             pText = NULL;
  184.         }
  185. }
  186.  
  187.  
  188. /////////////////////////////////////////////////////////////////////////////
  189. // CItemData::GetFont - Return the item's font.
  190.  
  191. CFontHolder *CItemData::GetFont()
  192. {
  193.     return pFontHolder;
  194. }
  195.  
  196.  
  197. /////////////////////////////////////////////////////////////////////////////
  198. // CItemData::SetFont - Set the item's font.
  199.  
  200. void CItemData::SetFont(LPFONTDISP pNewFontDisp)
  201. {
  202.    if (pNewFontDisp)
  203.    {
  204.         if (!pFontHolder)
  205.         {
  206.             pFontHolder = new CFontHolder(NULL);
  207.         }
  208.         pFontHolder->InitializeFont(NULL, pNewFontDisp);
  209.     }
  210.     else
  211.         if (pFontHolder)
  212.         {
  213.             delete pFontHolder;
  214.             pFontHolder = NULL;
  215.         }
  216. }
  217.  
  218.  
  219. /////////////////////////////////////////////////////////////////////////////
  220. // CItemData::GetPicture - Return the item's picture.
  221.  
  222. CPictureHolder *CItemData::GetPicture()
  223. {
  224.     return pPicHolder;
  225. }
  226.  
  227.  
  228. /////////////////////////////////////////////////////////////////////////////
  229. // CItemData::SetPicture - Set the item's picture.
  230.  
  231. void CItemData::SetPicture(LPPICTUREDISP pNewPicDisp)
  232. {
  233.     if (pNewPicDisp)
  234.     {
  235.         if (!pPicHolder)
  236.         {
  237.             pPicHolder = new CPictureHolder;
  238.         }
  239.          pPicHolder->SetPictureDispatch(pNewPicDisp);
  240.     }
  241.     else
  242.         if (pPicHolder)
  243.         {
  244.             delete pPicHolder;
  245.             pPicHolder = NULL;
  246.         }
  247. }
  248.  
  249.  
  250. IMPLEMENT_DYNCREATE(CXlistCtrl, COleControl)
  251.  
  252.  
  253. /////////////////////////////////////////////////////////////////////////////
  254. // Message map
  255.  
  256. BEGIN_MESSAGE_MAP(CXlistCtrl, COleControl)
  257.     //{{AFX_MSG_MAP(CXlistCtrl)
  258.     ON_MESSAGE(OCM_COMMAND, OnOcmCommand)
  259.     ON_WM_ERASEBKGND()
  260.     ON_MESSAGE(OCM_DRAWITEM,    OnOcmDrawItem)
  261.     ON_MESSAGE(OCM_MEASUREITEM, OnOcmMeasureItem)
  262.     //}}AFX_MSG_MAP
  263.     ON_OLEVERB(AFX_IDS_VERB_PROPERTIES, OnProperties)
  264. END_MESSAGE_MAP()
  265.  
  266.  
  267. /////////////////////////////////////////////////////////////////////////////
  268. // Dispatch map
  269.  
  270. BEGIN_DISPATCH_MAP(CXlistCtrl, COleControl)
  271.     //{{AFX_DISPATCH_MAP(CXlistCtrl)
  272.     DISP_PROPERTY_NOTIFY(CXlistCtrl, "InvertFlag", m_invertFlag, OnInvertFlagChanged, VT_BOOL)
  273.     DISP_FUNCTION(CXlistCtrl, "RemoveItem", RemoveItem, VT_EMPTY, VTS_I2)
  274.     DISP_FUNCTION(CXlistCtrl, "Clear", Clear, VT_EMPTY, VTS_NONE)
  275.     DISP_FUNCTION(CXlistCtrl, "AddTextFontItem", AddTextFontItem, VT_EMPTY, VTS_I2 VTS_BSTR VTS_FONT)
  276.     DISP_FUNCTION(CXlistCtrl, "AddTextItem", AddTextItem, VT_EMPTY, VTS_I2 VTS_BSTR)
  277.     DISP_FUNCTION(CXlistCtrl, "AddPicItem", AddPicItem, VT_EMPTY, VTS_I2 VTS_PICTURE)
  278.     DISP_PROPERTY_PARAM(CXlistCtrl, "ItemBackColor", GetItemBackColor, SetItemBackColor, VT_COLOR, VTS_I2)
  279.     DISP_PROPERTY_PARAM(CXlistCtrl, "ItemForeColor", GetItemForeColor, SetItemForeColor, VT_COLOR, VTS_I2)
  280.     DISP_PROPERTY_PARAM(CXlistCtrl, "ItemText", GetItemText, SetItemText, VT_BSTR, VTS_I2)
  281.     DISP_PROPERTY_PARAM(CXlistCtrl, "ItemFont", GetItemFont, SetItemFont, VT_FONT, VTS_I2)
  282.     DISP_PROPERTY_PARAM(CXlistCtrl, "ItemPicture", GetItemPicture, SetItemPicture, VT_PICTURE, VTS_I2)
  283.     //}}AFX_DISPATCH_MAP
  284.     DISP_FUNCTION_ID(CXlistCtrl, "AboutBox", DISPID_ABOUTBOX, AboutBox, VT_EMPTY, VTS_NONE)
  285. END_DISPATCH_MAP()
  286.  
  287.  
  288. /////////////////////////////////////////////////////////////////////////////
  289. // Event map
  290.  
  291. BEGIN_EVENT_MAP(CXlistCtrl, COleControl)
  292.     //{{AFX_EVENT_MAP(CXlistCtrl)
  293.     //}}AFX_EVENT_MAP
  294. END_EVENT_MAP()
  295.  
  296.  
  297. /////////////////////////////////////////////////////////////////////////////
  298. // Property pages
  299.  
  300. // TODO: Add more property pages as needed.  Remember to increase the count!
  301. BEGIN_PROPPAGEIDS(CXlistCtrl, 1)
  302.     PROPPAGEID(CXlistPropPage::guid)
  303. END_PROPPAGEIDS(CXlistCtrl)
  304.  
  305.  
  306. /////////////////////////////////////////////////////////////////////////////
  307. // Initialize class factory and guid
  308.  
  309. IMPLEMENT_OLECREATE_EX(CXlistCtrl, "XLIST.XlistCtrl.1",
  310.     0x37446b99, 0x5870, 0x101b, 0xb5, 0x7b, 0x0, 0x60, 0x8c, 0xc9, 0x6a, 0xfa)
  311.  
  312.  
  313. /////////////////////////////////////////////////////////////////////////////
  314. // Type library ID and version
  315.  
  316. IMPLEMENT_OLETYPELIB(CXlistCtrl, _tlid, _wVerMajor, _wVerMinor)
  317.  
  318.  
  319. /////////////////////////////////////////////////////////////////////////////
  320. // Interface IDs
  321.  
  322. const IID BASED_CODE IID_DXlist =
  323.         { 0x37446b9a, 0x5870, 0x101b, { 0xb5, 0x7b, 0x0, 0x60, 0x8c, 0xc9, 0x6a, 0xfa } };
  324. const IID BASED_CODE IID_DXlistEvents =
  325.         { 0x37446b9b, 0x5870, 0x101b, { 0xb5, 0x7b, 0x0, 0x60, 0x8c, 0xc9, 0x6a, 0xfa } };
  326.  
  327.  
  328. /////////////////////////////////////////////////////////////////////////////
  329. // Control type information
  330.  
  331. static const DWORD BASED_CODE _dwXlistOleMisc =
  332.     OLEMISC_ACTIVATEWHENVISIBLE |
  333.     OLEMISC_SETCLIENTSITEFIRST |
  334.     OLEMISC_INSIDEOUT |
  335.     OLEMISC_CANTLINKINSIDE |
  336.     OLEMISC_RECOMPOSEONRESIZE;
  337.  
  338. IMPLEMENT_OLECTLTYPE(CXlistCtrl, IDS_XLIST, _dwXlistOleMisc)
  339.  
  340.  
  341. /////////////////////////////////////////////////////////////////////////////
  342. // CXlistCtrl::CXlistCtrlFactory::UpdateRegistry -
  343. // Adds or removes system registry entries for CXlistCtrl
  344.  
  345. BOOL CXlistCtrl::CXlistCtrlFactory::UpdateRegistry(BOOL bRegister)
  346. {
  347.     if (bRegister)
  348.         return AfxOleRegisterControlClass(
  349.             AfxGetInstanceHandle(),
  350.             m_clsid,
  351.             m_lpszProgID,
  352.             IDS_XLIST,
  353.             IDB_XLIST,
  354.             FALSE,                      //  Not insertable
  355.             _dwXlistOleMisc,
  356.             _tlid,
  357.             _wVerMajor,
  358.             _wVerMinor);
  359.     else
  360.         return AfxOleUnregisterClass(m_clsid, m_lpszProgID);
  361. }
  362.  
  363.  
  364. /////////////////////////////////////////////////////////////////////////////
  365. // CXlistCtrl::CXlistCtrl - Constructor
  366.  
  367. CXlistCtrl::CXlistCtrl()
  368. {
  369.     InitializeIIDs(&IID_DXlist, &IID_DXlistEvents);
  370.  
  371.     m_itemDefHeight = 0;
  372.     m_sBorderStyle = 1;
  373. }
  374.  
  375.  
  376. /////////////////////////////////////////////////////////////////////////////
  377. // CXlistCtrl::~CXlistCtrl - Destructor
  378.  
  379. CXlistCtrl::~CXlistCtrl()
  380. {
  381.     // Cleanup any and all CItemData objects
  382.  
  383.     for (int i=0; i<=m_itemData.GetUpperBound(); i++)
  384.     {
  385.         CItemData* pItem = (CItemData*)m_itemData.GetAt(i);
  386.  
  387.         if (pItem != NULL)
  388.             delete pItem;
  389.     }
  390.  
  391.     m_itemData.RemoveAll();
  392. }
  393.  
  394.  
  395. BOOL CXlistCtrl::PreTranslateMessage(MSG* pMsg)
  396. {
  397.     if (pMsg->message == WM_KEYDOWN)
  398.     {
  399.         if (pMsg->wParam == VK_DOWN || pMsg->wParam == VK_UP)
  400.         {
  401.             SendMessage(pMsg->message, pMsg->wParam, pMsg->lParam);
  402.             return TRUE;
  403.         }
  404.     }
  405.     return FALSE;
  406. }
  407.  
  408. /////////////////////////////////////////////////////////////////////////////
  409. // CXlistCtrl::OnDraw - Drawing function
  410.  
  411. void CXlistCtrl::OnDraw(
  412.             CDC* pdc, const CRect& rcBounds, const CRect&)
  413. {
  414.     LPRECT      lpr;
  415.     CBrush      br;
  416.  
  417.     lpr = (LPRECT)(LPCRECT)rcBounds;
  418.  
  419.     // Paint background with the ambient background color
  420.     br.CreateSolidBrush(TranslateColor(AmbientBackColor()));
  421.     pdc->FillRect(lpr, &br);
  422.  
  423.     // Adjust rectangle size to account for listbox idiosyncracies
  424.     // (it paints its own nonclient stuff during WM_PAINT)
  425.     CRect rect(rcBounds);
  426.  
  427.     if (!pdc->IsKindOf(RUNTIME_CLASS(CPaintDC)))
  428.     {
  429.         if (m_bUIActive && m_pRectTracker != NULL)
  430.         {
  431.             UINT nAdjust = 2 * m_pRectTracker->m_nHandleSize;
  432.             rect.right -= nAdjust;
  433.             rect.bottom -= nAdjust;
  434.         }
  435.  
  436.         if (m_bInPlaceActive && (GetStyle() & WS_VSCROLL))
  437.             rect.right -= GetSystemMetrics(SM_CXVSCROLL);
  438.     }
  439.  
  440.     DoSuperclassPaint(pdc, rect);
  441. }
  442.  
  443.  
  444. /////////////////////////////////////////////////////////////////////////////
  445. // CXlistCtrl::DoPropExchange - Persistence support
  446.  
  447. void CXlistCtrl::DoPropExchange(CPropExchange* pPX)
  448. {
  449.     ExchangeVersion(pPX, MAKELONG(_wVerMinor, _wVerMajor));
  450.     COleControl::DoPropExchange(pPX);
  451.  
  452.     PX_Bool(pPX, _T("InvertFlag"), m_invertFlag, TRUE);
  453. }
  454.  
  455.  
  456. /////////////////////////////////////////////////////////////////////////////
  457. // CXlistCtrl::OnResetState - Reset control to default state
  458.  
  459. void CXlistCtrl::OnResetState()
  460. {
  461.     Clear();
  462.  
  463.     COleControl::OnResetState();  // Resets defaults found in DoPropExchange
  464. }
  465.  
  466.  
  467. /////////////////////////////////////////////////////////////////////////////
  468. // CXlistCtrl::AboutBox - Display an "About" box to the user
  469.  
  470. void CXlistCtrl::AboutBox()
  471. {
  472.     CDialog dlgAbout(IDD_ABOUTBOX_XLIST);
  473.     dlgAbout.DoModal();
  474. }
  475.  
  476.  
  477. /////////////////////////////////////////////////////////////////////////////
  478. // CXlistCtrl::PreCreateWindow - Modify parameters for CreateWindowEx
  479.  
  480. BOOL CXlistCtrl::PreCreateWindow(CREATESTRUCT& cs)
  481. {
  482.     cs.lpszClass = _T("LISTBOX");
  483.     cs.style |= LBS_STANDARD | LBS_OWNERDRAWVARIABLE;
  484.     return COleControl::PreCreateWindow(cs);
  485. }
  486.  
  487.  
  488. /////////////////////////////////////////////////////////////////////////////
  489. // CXlistCtrl::IsSubclassedControl - This is a subclassed control
  490.  
  491. BOOL CXlistCtrl::IsSubclassedControl()
  492. {
  493.     return TRUE;
  494. }
  495.  
  496.  
  497. /////////////////////////////////////////////////////////////////////////////
  498. // CXlistCtrl::OnOcmCommand - Handle command messages
  499.  
  500. LRESULT CXlistCtrl::OnOcmCommand(WPARAM wParam, LPARAM lParam)
  501. {
  502. #ifdef _WIN32
  503.     WORD wNotifyCode = HIWORD(wParam);
  504.     lParam;
  505. #else
  506.     WORD wNotifyCode = HIWORD(lParam);
  507.     wParam;
  508. #endif
  509.  
  510.     return 0;
  511. }
  512.  
  513.  
  514. /////////////////////////////////////////////////////////////////////////////
  515. // CXlistCtrl::OnInvertFlagChanged - Respond when the invert flag is changed.
  516.  
  517. void CXlistCtrl::OnInvertFlagChanged()
  518. {
  519.     SetModifiedFlag(TRUE);
  520.     InvalidateControl();
  521. }
  522.  
  523.  
  524. /////////////////////////////////////////////////////////////////////////////
  525. // CXlistCtrl::GetItemBackColor - Return an item's background color.
  526.  
  527. OLE_COLOR CXlistCtrl::GetItemBackColor(short nIndex)
  528. {
  529.     OLE_COLOR *pColor;
  530.     if ((int)nIndex <= m_itemData.GetSize() - 1)
  531.     {
  532.         CItemData *pItemData = (CItemData *)m_itemData.GetAt(nIndex);
  533.         pColor = pItemData->GetBackColor();
  534.         if (pColor)
  535.             return *pColor;
  536.     }
  537.     return (OLE_COLOR)-1;
  538. }
  539.  
  540.  
  541. /////////////////////////////////////////////////////////////////////////////
  542. // CXlistCtrl::SetItemBackColor - Set an item's background color.
  543.  
  544. void CXlistCtrl::SetItemBackColor(short nIndex, OLE_COLOR newValue)
  545. {
  546.     OLE_COLOR *pColor;
  547.     if ((int)nIndex <= m_itemData.GetSize() - 1)
  548.     {
  549.         CItemData *pItemData = (CItemData *)m_itemData.GetAt(nIndex);
  550.         newValue == -1 ? pColor = NULL : pColor = &newValue;
  551.  
  552.         TRY
  553.         {
  554.             pItemData->SetBackColor(pColor);
  555.         }
  556.         CATCH(CMemoryException, e)
  557.         {
  558.             ThrowError(CTL_E_OUTOFMEMORY, AFX_IDP_E_OUTOFMEMORY);
  559.         }
  560.         END_CATCH
  561.  
  562.         SetModifiedFlag(TRUE);
  563.         InvalidateControl();
  564.     }
  565. }
  566.  
  567.  
  568. /////////////////////////////////////////////////////////////////////////////
  569. // CXlistCtrl::GetItemForeColor - Return an item's foreground color.
  570.  
  571. OLE_COLOR CXlistCtrl::GetItemForeColor(short nIndex)
  572. {
  573.     OLE_COLOR *pColor;
  574.     if ((int)nIndex <= m_itemData.GetSize() - 1)
  575.     {
  576.         CItemData *pItemData = (CItemData *)m_itemData.GetAt(nIndex);
  577.         pColor = pItemData->GetForeColor();
  578.         if (pColor)
  579.             return *pColor;
  580.     }
  581.     return (OLE_COLOR)-1;
  582. }
  583.  
  584.  
  585. /////////////////////////////////////////////////////////////////////////////
  586. // CXlistCtrl::SetItemForeColor - Set an item's foreground color.
  587.  
  588. void CXlistCtrl::SetItemForeColor(short nIndex, OLE_COLOR newValue)
  589. {
  590.     OLE_COLOR *pColor;
  591.     if ((int)nIndex <= m_itemData.GetSize() - 1)
  592.     {
  593.         CItemData *pItemData = (CItemData *)m_itemData.GetAt(nIndex);
  594.         newValue == -1 ? pColor = NULL : pColor = &newValue;
  595.         TRY
  596.         {
  597.             pItemData->SetForeColor(pColor);
  598.         }
  599.         CATCH (CMemoryException, e)
  600.         {
  601.             ThrowError(CTL_E_OUTOFMEMORY, AFX_IDP_E_OUTOFMEMORY);
  602.         }
  603.         END_CATCH
  604.  
  605.         SetModifiedFlag(TRUE);
  606.         InvalidateControl();
  607.     }
  608. }
  609.  
  610.  
  611. /////////////////////////////////////////////////////////////////////////////
  612. // CXlistCtrl::GetItemText - Get an item's text.
  613.  
  614. BSTR CXlistCtrl::GetItemText(short nIndex)
  615. {
  616.     TCHAR textBuffer[MAXTEXTLEN];
  617.     LPTSTR lpTextBuffer = (LPTSTR)textBuffer;
  618.  
  619.     if ((int)nIndex <= m_itemData.GetSize() - 1)
  620.     {
  621.         CItemData *pItemData = (CItemData *)m_itemData.GetAt(nIndex);
  622.         pItemData->GetText(lpTextBuffer, sizeof(textBuffer)/sizeof(*textBuffer));
  623.  
  624.         CString s = lpTextBuffer;
  625.         return s.AllocSysString();
  626.     }
  627.     return NULL;
  628. }
  629.  
  630.  
  631. /////////////////////////////////////////////////////////////////////////////
  632. // CXlistCtrl::SetItemText - Set an item's text.
  633.  
  634. void CXlistCtrl::SetItemText(short nIndex, LPCTSTR lpszNewValue)
  635. {
  636.     if ((int)nIndex <= m_itemData.GetSize() - 1)
  637.     {
  638.         CItemData *pItemData = (CItemData *)m_itemData.GetAt(nIndex);
  639.         TRY
  640.         {
  641.             pItemData->SetText(lpszNewValue);
  642.         }
  643.         CATCH (CMemoryException, e)
  644.         {
  645.             ThrowError(CTL_E_OUTOFMEMORY, AFX_IDP_E_OUTOFMEMORY);
  646.         }
  647.         END_CATCH
  648.  
  649.         SetModifiedFlag(TRUE);
  650.         InvalidateControl();
  651.     }
  652. }
  653.  
  654.  
  655. /////////////////////////////////////////////////////////////////////////////
  656. // CXlistCtrl::GetItemFont - Return an item's font.
  657.  
  658. LPFONTDISP CXlistCtrl::GetItemFont(short nIndex)
  659. {
  660.     if ((int)nIndex <= m_itemData.GetSize() - 1)
  661.     {
  662.         CItemData *pItemData = (CItemData *)m_itemData.GetAt(nIndex);
  663.         CFontHolder *pFontHolder = pItemData->GetFont();
  664.         if (pFontHolder)
  665.             return pFontHolder->GetFontDispatch();
  666.     }
  667.     return NULL;
  668. }
  669.  
  670.  
  671. /////////////////////////////////////////////////////////////////////////////
  672. // CXlistCtrl::SetItemFont - Set an item's font.
  673.  
  674. void CXlistCtrl::SetItemFont(short nIndex, LPFONTDISP newValue)
  675. {
  676.     if ((int)nIndex <= m_itemData.GetSize() - 1)
  677.     {
  678.         CItemData *pItemData = (CItemData *)m_itemData.GetAt(nIndex);
  679.         TRY
  680.         {
  681.             pItemData->SetFont(newValue);
  682.         }
  683.         CATCH (CMemoryException, e)
  684.         {
  685.             ThrowError(CTL_E_OUTOFMEMORY, AFX_IDP_E_OUTOFMEMORY);
  686.         }
  687.         END_CATCH
  688.  
  689.         // Update item positions because font size may have changed
  690.         UpdateItems();
  691.  
  692.         SetModifiedFlag(TRUE);
  693.         InvalidateControl();
  694.     }
  695. }
  696.  
  697.  
  698. /////////////////////////////////////////////////////////////////////////////
  699. // CXlistCtrl:GetItemPicture - Get an item's picture.
  700.  
  701. LPPICTUREDISP CXlistCtrl::GetItemPicture(short nIndex)
  702. {
  703.     if ((int)nIndex <= m_itemData.GetSize() - 1)
  704.     {
  705.         CItemData *pItemData = (CItemData *)m_itemData.GetAt(nIndex);
  706.         CPictureHolder *pPictureHolder = pItemData->GetPicture();
  707.         if (pPictureHolder)
  708.             return pPictureHolder->GetPictureDispatch();
  709.     }
  710.     return NULL;
  711. }
  712.  
  713.  
  714. /////////////////////////////////////////////////////////////////////////////
  715. // CXlistCtrl::SetItemPicture - Set an item's picture.
  716.  
  717. void CXlistCtrl::SetItemPicture(short nIndex, LPPICTUREDISP newValue)
  718. {
  719.     if ((int)nIndex <= m_itemData.GetSize() - 1)
  720.     {
  721.         CItemData *pItemData = (CItemData *)m_itemData.GetAt(nIndex);
  722.         TRY
  723.         {
  724.             pItemData->SetPicture(newValue);
  725.         }
  726.         CATCH (CMemoryException, e)
  727.         {
  728.             ThrowError(CTL_E_OUTOFMEMORY, AFX_IDP_E_OUTOFMEMORY);
  729.         }
  730.         END_CATCH
  731.  
  732.         // Update item positions because picture size may have changed
  733.         UpdateItems();
  734.  
  735.         SetModifiedFlag(TRUE);
  736.         InvalidateControl();
  737.     }
  738. }
  739.  
  740.  
  741. /////////////////////////////////////////////////////////////////////////////
  742. // CXlistCtrl::AddTextItem - Add a text item.
  743.  
  744. void CXlistCtrl::AddTextItem(short nIndex, LPCTSTR lpstrText)
  745. {
  746.     AddItem(nIndex, lpstrText, NULL, NULL);
  747. }
  748.  
  749.  
  750. /////////////////////////////////////////////////////////////////////////////
  751. // CXlistCtrl::AddTextFontItem - Add a text item which has its own font.
  752.  
  753. void CXlistCtrl::AddTextFontItem(short nIndex, LPCTSTR lpstrText, LPFONTDISP font)
  754. {
  755.     AddItem(nIndex, lpstrText, font, NULL);
  756. }
  757.  
  758.  
  759. /////////////////////////////////////////////////////////////////////////////
  760. // CXlistCtrl::AddPicItem - Add a picture item.
  761.  
  762. void CXlistCtrl::AddPicItem(short nIndex, LPPICTUREDISP pic)
  763. {
  764.     AddItem(nIndex, NULL, NULL, pic);
  765. }
  766.  
  767.  
  768. /////////////////////////////////////////////////////////////////////////////
  769. // CXlistCtrl::AddItem - Add an item.
  770.  
  771. void CXlistCtrl::AddItem(short nIndex, LPCTSTR lpstrText, LPFONTDISP lpFontDisp, LPPICTUREDISP lpPicDisp)
  772. {
  773.     if ((int)nIndex <= m_itemData.GetSize())
  774.     {
  775.         // Init item data
  776.         CItemData* pItemData = NULL;
  777.  
  778.         TRY
  779.         {
  780.             pItemData = new CItemData(lpstrText, lpFontDisp, lpPicDisp);
  781.         }
  782.         CATCH (CMemoryException, e)
  783.         {
  784.             ThrowError(CTL_E_OUTOFMEMORY, AFX_IDP_E_OUTOFMEMORY);
  785.         }
  786.         END_CATCH
  787.  
  788.         // Add item data to collection
  789.         m_itemData.InsertAt(nIndex, pItemData);
  790.  
  791.         // Add item text to listbox
  792.         SendMessage(LB_INSERTSTRING, nIndex, (long)lpstrText);
  793.  
  794.         SetModifiedFlag(TRUE);
  795.         InvalidateControl();
  796.     }
  797. }
  798.  
  799.  
  800. /////////////////////////////////////////////////////////////////////////////
  801. // CXlistCtrl::RemoveItem - Remove an item.
  802.  
  803. void CXlistCtrl::RemoveItem(short nIndex)
  804. {
  805.     if ((int)nIndex <= m_itemData.GetSize() - 1)
  806.     {
  807.         // Free item data
  808.         delete m_itemData.GetAt(nIndex);
  809.  
  810.         // Remove item from item array
  811.         m_itemData.RemoveAt(nIndex);
  812.  
  813.         // Remove item text from listbox
  814.         SendMessage(LB_DELETESTRING, nIndex, 0L);
  815.  
  816.         SetModifiedFlag(TRUE);
  817.         InvalidateControl();
  818.     }
  819. }
  820.  
  821.  
  822. /////////////////////////////////////////////////////////////////////////////
  823. // CXlistCtrl::Clear - Clear all items in the list.
  824.  
  825. void CXlistCtrl::Clear()
  826. {
  827.     if (m_itemData.GetSize() > 0)
  828.     {
  829.         // For each item
  830.         for (int i = 0; i < m_itemData.GetSize(); i++)
  831.         {
  832.             // Free item data
  833.             delete m_itemData.GetAt( i );
  834.         }
  835.  
  836.         // Remove all items from item array
  837.         m_itemData.RemoveAll();
  838.  
  839.         // Remove all text from listbox
  840.         SendMessage(LB_RESETCONTENT, 0, 0L);
  841.  
  842.         SetModifiedFlag(TRUE);
  843.         InvalidateControl();
  844.     }
  845. }
  846.  
  847.  
  848. /////////////////////////////////////////////////////////////////////////////
  849. // CXlistCtrl::OnAmbientPropertyChange - If the ambient font has changed,
  850. // update default item height and item positions.
  851.  
  852. void CXlistCtrl::OnAmbientPropertyChange(DISPID dispid)
  853. {
  854.     if (dispid == DISPID_AMBIENT_FONT)
  855.     {
  856.         // Update item default height
  857.         UpdateDefHeight();
  858.  
  859.         // Update item positions
  860.         UpdateItems();
  861.     }
  862. }
  863.  
  864.  
  865. /////////////////////////////////////////////////////////////////////////////
  866. // CXlistCtrl::OnEraseBkgnd
  867.  
  868. BOOL CXlistCtrl::OnEraseBkgnd(CDC* pDC)
  869. {
  870.     return COleControl::OnEraseBkgnd(pDC);
  871. }
  872.  
  873.  
  874. /////////////////////////////////////////////////////////////////////////////
  875. // CXlistCtrl::OnSetClientSite - Set the default item height.
  876.  
  877. void CXlistCtrl::OnSetClientSite()
  878. {
  879.     COleControl::OnSetClientSite();
  880.  
  881.     UpdateDefHeight();
  882. }
  883.  
  884.  
  885. /////////////////////////////////////////////////////////////////////////////
  886. // CXlistCtrl::OnOcmDrawItem - Draw an item.
  887.  
  888. LRESULT CXlistCtrl::OnOcmDrawItem(WPARAM, LPARAM lParam)
  889. {
  890.     DrawItem((LPDRAWITEMSTRUCT)lParam);
  891.  
  892.     return 1;
  893. }
  894.  
  895.  
  896. /////////////////////////////////////////////////////////////////////////////
  897. // CXlistCtrl::DrawItem - Draw an item.
  898.  
  899. void CXlistCtrl::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
  900. {
  901.     CItemData *pItemData;
  902.     CDC *pdc;
  903.     CPen* pOldPen;
  904.  
  905.     // Return if id is invalid
  906.     if ( (lpDrawItemStruct->itemID == (UINT)-1) ||
  907.          ((int)lpDrawItemStruct->itemID >= m_itemData.GetSize()))
  908.         return;
  909.  
  910.     // Get item data
  911.     pItemData = (CItemData *)m_itemData.GetAt(lpDrawItemStruct->itemID);
  912.  
  913.     // Construct CDC object for drawing
  914.     pdc = CDC::FromHandle(lpDrawItemStruct->hDC);
  915.  
  916.     switch (lpDrawItemStruct->itemAction)
  917.     {
  918.         case ODA_DRAWENTIRE:
  919.  
  920.              // Brush item background and set background color
  921.             SelectItemBackColor(pItemData, &lpDrawItemStruct->rcItem, pdc);
  922.  
  923.             // Draw item's picture
  924.             DrawItemPicture(pItemData, &lpDrawItemStruct->rcItem, pdc);
  925.  
  926.             // Draw item's text
  927.             DrawItemText(pItemData, &lpDrawItemStruct->rcItem, pdc);
  928.  
  929.             // Break if item is not selected
  930.             if (lpDrawItemStruct->itemState != ODS_SELECTED)
  931.                 break;
  932.  
  933.         case ODA_SELECT:
  934.  
  935.             // If invert flag is set, invert item when selected
  936.             if (m_invertFlag)
  937.                 pdc->InvertRect(&lpDrawItemStruct->rcItem);
  938.             break;
  939.  
  940.         case ODA_FOCUS:
  941.  
  942.             // Draw focus rect when item gets the focus
  943.             pOldPen = (CPen*)pdc->SelectStockObject(BLACK_PEN);
  944.             pdc->DrawFocusRect(&lpDrawItemStruct->rcItem);
  945.             pdc->SelectObject(pOldPen);
  946.             break;
  947.     }
  948. }
  949.  
  950.  
  951. /////////////////////////////////////////////////////////////////////////////
  952. // CXlistCtrl::SelectItemBackColor - Brushes an item's background and
  953. // selects the background color
  954.  
  955. void CXlistCtrl::SelectItemBackColor(CItemData *pItemData, LPRECT lpRect, CDC *pdc)
  956. {
  957.     OLE_COLOR color;
  958.     OLE_COLOR *pColor;
  959.  
  960.     // Get item background color
  961.     pColor = pItemData->GetBackColor();
  962.  
  963.     // If background color is not specified, use ambient background color
  964.     if (!pColor)
  965.     {
  966.         color = AmbientBackColor();
  967.         pColor = (OLE_COLOR *)&color;
  968.     }
  969.  
  970.     // Brush background
  971.     CBrush brush;
  972.     brush.CreateSolidBrush(TranslateColor(*pColor));
  973.     pdc->FillRect(lpRect, &brush);
  974.  
  975.     // Set background color
  976.     pdc->SetBkMode(TRANSPARENT);
  977. }
  978.  
  979.  
  980. /////////////////////////////////////////////////////////////////////////////
  981. // CXlistCtrl::DrawItemPicture - Draws an item's picture.  Draws nothing if
  982. // the item has no picture.
  983.  
  984. void CXlistCtrl::DrawItemPicture(CItemData *pItemData, LPRECT lpRect, CDC *pdc)
  985. {
  986.     CPictureHolder *pPicHolder;
  987.     LPPICTUREDISP pPicDisp;
  988.  
  989.     int picHeight;
  990.     int picWidth;
  991.     long tempPicHeight;
  992.     long tempPicWidth;
  993.  
  994.     // Get item picture
  995.     pPicHolder = pItemData->GetPicture();
  996.  
  997.     // Draw item picture
  998.     if (pPicHolder)
  999.     {
  1000.         // Get height and width of picture
  1001.         pPicDisp = pPicHolder->GetPictureDispatch();
  1002.         tempPicHeight = GetPictureHeight(pPicDisp);
  1003.         tempPicWidth = GetPictureWidth(pPicDisp);
  1004.         pPicDisp->Release();
  1005.  
  1006.         // Convert height and width to pixels
  1007.         picHeight = XformHeightInHimetricToPixels(pdc->m_hDC, (int)LOWORD(tempPicHeight));
  1008.         picWidth = XformWidthInHimetricToPixels(pdc->m_hDC, (int)LOWORD(tempPicWidth));
  1009.  
  1010.         // Set up draw rect
  1011.         lpRect->right = lpRect->left + picWidth;
  1012.         lpRect->bottom = lpRect->top + picHeight;
  1013.  
  1014.         // Center rect
  1015.         lpRect->top += ITEMSPACING/2;
  1016.         lpRect->bottom += ITEMSPACING/2;
  1017.  
  1018.         // Draw picture
  1019.         pPicHolder->Render(pdc, *lpRect, *lpRect);
  1020.     }
  1021. }
  1022.  
  1023.  
  1024. /////////////////////////////////////////////////////////////////////////////
  1025. // CXlistCtrl::DrawItemText - Draws an item's text.  Draws nothing if the
  1026. // item has no text.
  1027.  
  1028. void CXlistCtrl::DrawItemText(CItemData *pItemData, LPRECT lpRect, CDC *pdc)
  1029. {
  1030.     TCHAR textBuffer[MAXTEXTLEN];
  1031.     LPTSTR lpTextBuffer = (LPTSTR)textBuffer;
  1032.     USHORT usLen;
  1033.     CFont* pOldFont;
  1034.  
  1035.     // Get item text
  1036.     pItemData->GetText(lpTextBuffer,
  1037.         sizeof(textBuffer)/sizeof(*textBuffer));
  1038.  
  1039.     // If item has text
  1040.     usLen = (USHORT)_tcslen(lpTextBuffer);
  1041.     if (usLen)
  1042.     {
  1043.         // Set item foreground color
  1044.         SelectItemForeColor(pItemData, pdc);
  1045.  
  1046.         // Select item font
  1047.         CFontHolder fontHolder(NULL);
  1048.         pOldFont = SelectItemFont(pItemData, pdc, fontHolder);
  1049.  
  1050.         // Draw text
  1051.         pdc->ExtTextOut(lpRect->left, lpRect->top, ETO_CLIPPED, lpRect, lpTextBuffer, usLen, NULL);
  1052.  
  1053.         // Reselect old font
  1054.         pdc->SelectObject(pOldFont);
  1055.     }
  1056. }
  1057.  
  1058.  
  1059. /////////////////////////////////////////////////////////////////////////////
  1060. // CXlistCtrl::SelectItemForeColor - Selects item's foreground color
  1061.  
  1062. void CXlistCtrl::SelectItemForeColor(CItemData *pItemData, CDC *pdc)
  1063. {
  1064.     OLE_COLOR color;
  1065.     OLE_COLOR *pColor;
  1066.  
  1067.     // Get item foreground color
  1068.     pColor = pItemData->GetForeColor();
  1069.     if (!pColor)
  1070.     {
  1071.         // If foreground color is not specified, use ambient foreground color
  1072.         color = AmbientForeColor();
  1073.         pColor = (OLE_COLOR *)&color;
  1074.     }
  1075.     pdc->SetTextColor(TranslateColor(*pColor));
  1076. }
  1077.  
  1078.  
  1079. /////////////////////////////////////////////////////////////////////////////
  1080. // CXlistCtrl::SelectItemFont - Selects item's font
  1081.  
  1082. CFont* CXlistCtrl::SelectItemFont(CItemData *pItemData, CDC *pdc,
  1083.     CFontHolder& fontHolder)
  1084. {
  1085.     CFontHolder *pFontHolder;
  1086.     CFont* pOldFont;
  1087.     LPFONTDISP pFontDisp;
  1088.  
  1089.     // Get item font
  1090.     pFontHolder = pItemData->GetFont();
  1091.  
  1092.     // If font is not specified, use ambient font
  1093.     if (!pFontHolder)
  1094.     {
  1095.         pFontHolder = &fontHolder;
  1096.         pFontDisp = AmbientFont();
  1097.         pFontHolder->InitializeFont(NULL, pFontDisp);
  1098.         if (pFontDisp != NULL)
  1099.             pFontDisp->Release();
  1100.     }
  1101.  
  1102.     pOldFont = SelectFontObject(pdc, *pFontHolder);
  1103.     return pOldFont;
  1104. }
  1105.  
  1106.  
  1107. /////////////////////////////////////////////////////////////////////////////
  1108. // CXlistCtrl::OnOcmMeasureItem - Return the height of an item.
  1109.  
  1110. LRESULT CXlistCtrl::OnOcmMeasureItem(WPARAM, LPARAM lParam)
  1111. {
  1112.     MeasureItem((LPMEASUREITEMSTRUCT)lParam);
  1113.  
  1114.     return 1;
  1115. }
  1116.  
  1117.  
  1118. /////////////////////////////////////////////////////////////////////////////
  1119. // CXlistCtrl::MeasureItem - Return the height of an item.
  1120.  
  1121. void CXlistCtrl::MeasureItem
  1122. (
  1123.     LPMEASUREITEMSTRUCT lpMI
  1124. )
  1125. {
  1126.     CItemData *pItemData;
  1127.     int textHeight;
  1128.     int picHeight;
  1129.     int tempHeight;
  1130.  
  1131.     // Return if id is invalid
  1132.     if ((lpMI->itemID == 0xffff) || ((int)lpMI->itemID >= m_itemData.GetSize()))
  1133.         return;
  1134.  
  1135.     pItemData = (CItemData *)m_itemData.GetAt(lpMI->itemID);
  1136.  
  1137.     // Get item's text height - zero if item has no text
  1138.     textHeight = GetItemTextHeight(pItemData);
  1139.  
  1140.     // Get item's picture height - zero if item has no picture
  1141.     picHeight = GetItemPictureHeight(pItemData);
  1142.  
  1143.     // Calculate item height using font height, picture height and spacing
  1144.  
  1145.     // tempHeight = max of textHeight and picHeight
  1146.     tempHeight = (textHeight > picHeight)  ? textHeight : picHeight;
  1147.  
  1148.     // if zero, set to default item height, else add item spacing
  1149.     tempHeight = (tempHeight == 0) ? m_itemDefHeight : tempHeight + ITEMSPACING;
  1150.  
  1151.     lpMI->itemHeight = tempHeight;
  1152. }
  1153.  
  1154.  
  1155. /////////////////////////////////////////////////////////////////////////////
  1156. // CXlistCtrl::GetItemTextHeight - Return an item's text height.  Returns
  1157. // zero if the item has no text.
  1158.  
  1159. int CXlistCtrl::GetItemTextHeight(CItemData *pItemData)
  1160. {
  1161.     TCHAR textBuffer[MAXTEXTLEN];
  1162.     LPTSTR lpTextBuffer = (LPTSTR)textBuffer;
  1163.  
  1164.     CFontHolder *pFontHolder;
  1165.     LPFONTDISP pFontDisp;
  1166.     int textHeight;
  1167.  
  1168.     // Get item text
  1169.     pItemData->GetText(lpTextBuffer,
  1170.         sizeof(textBuffer)/sizeof(*textBuffer));
  1171.  
  1172.     // If item has text
  1173.     if (_tcslen(lpTextBuffer) > 0)
  1174.     {
  1175.         // Get item font
  1176.         pFontHolder = pItemData->GetFont();
  1177.  
  1178.         if (pFontHolder)
  1179.         {
  1180.             // Get font dispatch ID
  1181.             pFontDisp = pFontHolder->GetFontDispatch();
  1182.  
  1183.             // Get font height using dispatch ID
  1184.             textHeight = GetFontHeight(pFontDisp);
  1185.             if (pFontDisp != NULL)
  1186.                 pFontDisp->Release();
  1187.  
  1188.             textHeight += ITEMSPACING;
  1189.         }
  1190.         else
  1191.             //If item font is not specified, use default item height
  1192.             textHeight = m_itemDefHeight;
  1193.     }
  1194.     else
  1195.         textHeight = 0;
  1196.  
  1197.     return textHeight;
  1198. }
  1199.  
  1200.  
  1201. /////////////////////////////////////////////////////////////////////////////
  1202. // CXlistCtrl::GetItemPictureHeight - Return an item's picture height.
  1203. // Returns zero if the item has no picture.
  1204.  
  1205. int CXlistCtrl::GetItemPictureHeight(CItemData *pItemData)
  1206. {
  1207.     CPictureHolder *pPicHolder;
  1208.     LPPICTUREDISP pPicDisp;
  1209.     long tempPicHeight;
  1210.     HDC dc;
  1211.     int picHeight;
  1212.  
  1213.     // Get item picture
  1214.     pPicHolder = pItemData->GetPicture();
  1215.  
  1216.     // If item has picture
  1217.     if (pPicHolder)
  1218.     {
  1219.         // Get picture height
  1220.         pPicDisp = pPicHolder->GetPictureDispatch();
  1221.         tempPicHeight = GetPictureHeight(pPicDisp);
  1222.         pPicDisp->Release();
  1223.  
  1224.         // Convert height to pixels
  1225.         dc = ::GetDC(m_hWnd);
  1226.         picHeight = XformHeightInHimetricToPixels(dc, (int)LOWORD(tempPicHeight));
  1227.         ::ReleaseDC(m_hWnd, dc);
  1228.     }
  1229.     else
  1230.         picHeight = 0;
  1231.  
  1232.     return picHeight;
  1233. }
  1234.  
  1235.  
  1236. /////////////////////////////////////////////////////////////////////////////
  1237. // CXlistCtrl::UpdateItems - Readds all items to reflect changes in size
  1238.  
  1239. void CXlistCtrl::UpdateItems()
  1240. {
  1241.     CItemData *pItemData;
  1242.     TCHAR textBuffer[MAXTEXTLEN];
  1243.     LPTSTR lpTextBuffer = (LPTSTR)textBuffer;
  1244.  
  1245.     if (m_itemData.GetSize() > 0)
  1246.     {
  1247.         // Delete items
  1248.         SendMessage(LB_RESETCONTENT, 0, 0L);
  1249.  
  1250.         // Readd items
  1251.         for (int i = 0; i < m_itemData.GetSize(); i++)
  1252.         {
  1253.             pItemData = (CItemData *)m_itemData.GetAt(i);
  1254.             pItemData->GetText(lpTextBuffer, sizeof(textBuffer)/sizeof(*textBuffer));
  1255.  
  1256.             // Add item text to listbox
  1257.             SendMessage(LB_INSERTSTRING, i, (long)lpTextBuffer);
  1258.         }
  1259.     }
  1260. }
  1261.  
  1262.  
  1263. /////////////////////////////////////////////////////////////////////////////
  1264. // CXlistCtrl::UpdateDefHeight - Update the default item height
  1265.  
  1266. void CXlistCtrl::UpdateDefHeight()
  1267. {
  1268.     CFontHolder fontHolder(NULL);
  1269.     LPFONTDISP pFontDisp;
  1270.  
  1271.     // Get height of ambient font
  1272.     pFontDisp = AmbientFont();
  1273.  
  1274.     if (pFontDisp != NULL)
  1275.     {
  1276.         m_itemDefHeight = GetFontHeight(pFontDisp);
  1277.         pFontDisp->Release();
  1278.     }
  1279.     if (m_itemDefHeight == 0)
  1280.     {
  1281.         // Initialize with default font
  1282.         fontHolder.InitializeFont(NULL, NULL);
  1283.         pFontDisp = fontHolder.GetFontDispatch();
  1284.         m_itemDefHeight = GetFontHeight(pFontDisp);
  1285.         pFontDisp->Release();
  1286.     }
  1287.  
  1288.     m_itemDefHeight += ITEMSPACING;
  1289. }
  1290.  
  1291.  
  1292. /////////////////////////////////////////////////////////////////////////////
  1293. // GetFontHeight - Return the height of the font with the specified
  1294. // dispatch id.
  1295.  
  1296. short GetFontHeight(LPFONTDISP lpfd)
  1297. {
  1298.     short fontHeight = 0;
  1299.     GetProperty(lpfd, DISPID_FONT_SIZE, VT_I2, (void*)&fontHeight);
  1300.     return fontHeight;
  1301. }
  1302.  
  1303.  
  1304. /////////////////////////////////////////////////////////////////////////////
  1305. // GetPictureHeight - Return the height of the picture with the specified
  1306. // dispatch id.
  1307.  
  1308. long GetPictureHeight(LPPICTUREDISP lppd)
  1309. {
  1310.     long picHeight = 0;
  1311.     GetProperty(lppd, DISPID_PICT_HEIGHT, VT_I4, (void*)&picHeight);
  1312.     return picHeight;
  1313. }
  1314.  
  1315.  
  1316. /////////////////////////////////////////////////////////////////////////////
  1317. // GetPictureWidth - Return the width of the picture with the specified
  1318. // dispatch id.
  1319.  
  1320. long GetPictureWidth(LPPICTUREDISP lppd)
  1321. {
  1322.     long picWidth = 0;
  1323.     GetProperty(lppd, DISPID_PICT_WIDTH, VT_I4, (void*)&picWidth);
  1324.     return picWidth;
  1325. }
  1326.  
  1327.  
  1328. /////////////////////////////////////////////////////////////////////////////
  1329. // GetProperty - Return the property with the specified dispatch id.
  1330.  
  1331. void GetProperty(LPDISPATCH lpd, short dispId, short propType, void *value)
  1332. {
  1333.     COleDispatchDriver driver;
  1334.  
  1335.     if (lpd)
  1336.     {
  1337.         driver.AttachDispatch(lpd, TRUE);
  1338.         if (driver.m_lpDispatch != NULL)
  1339.         {
  1340.             TRY
  1341.             {
  1342.                 driver.GetProperty(dispId, propType, value);
  1343.             }
  1344.             END_TRY
  1345.             driver.DetachDispatch();
  1346.         }
  1347.     }
  1348. }
  1349.  
  1350.  
  1351. /////////////////////////////////////////////////////////////////////////////
  1352. // XformWidthInHimetricToPixels - Transform the specified himetric width
  1353. // to pixels.
  1354.  
  1355. STDAPI_(int) XformWidthInHimetricToPixels(HDC hDC, int iWidthInHiMetric)
  1356. {
  1357.     int     iXppli;     // Pixels per logical inch along width
  1358.     int     iWidthInPix;
  1359.     BOOL    fSystemDC=FALSE;
  1360.  
  1361.     if (NULL==hDC)
  1362.     {
  1363.         hDC=GetDC(NULL);
  1364.         fSystemDC=TRUE;
  1365.     }
  1366.  
  1367.     iXppli = GetDeviceCaps (hDC, LOGPIXELSX);
  1368.  
  1369.     // We've got logical HIMETRIC along the display, convert to pixel units
  1370.     iWidthInPix = MAP_LOGHIM_TO_PIX(iWidthInHiMetric, iXppli);
  1371.  
  1372.     if (fSystemDC)
  1373.         ReleaseDC(NULL, hDC);
  1374.  
  1375.     return iWidthInPix;
  1376. }
  1377.  
  1378.  
  1379. /////////////////////////////////////////////////////////////////////////////
  1380. // XformHeightInHimetricToPixels - Transform the specified himetric height
  1381. // to pixels.
  1382.  
  1383. STDAPI_(int) XformHeightInHimetricToPixels(HDC hDC, int iHeightInHiMetric)
  1384. {
  1385.     int     iYppli;     // Pixels per logical inch along height
  1386.     int     iHeightInPix;
  1387.     BOOL    fSystemDC=FALSE;
  1388.  
  1389.     if (NULL==hDC)
  1390.     {
  1391.         hDC=GetDC(NULL);
  1392.         fSystemDC=TRUE;
  1393.     }
  1394.  
  1395.     iYppli = GetDeviceCaps (hDC, LOGPIXELSY);
  1396.  
  1397.     // We've got logical HIMETRIC along the display, convert to pixel units
  1398.     iHeightInPix = MAP_LOGHIM_TO_PIX(iHeightInHiMetric, iYppli);
  1399.  
  1400.     if (fSystemDC)
  1401.         ReleaseDC(NULL, hDC);
  1402.  
  1403.     return iHeightInPix;
  1404. }
  1405.