Demonstrates the use of GfxListCtrl control, CHyperlink class , CSystemTray class

Address Book demonstrates the use of GfxListCtrl control, CHyperlink class , CSystemTray class into one useful application. It also demonstrates dropdown tool button and well as using the template class CArray.

Even thought lot of programs at Codeguru come with samples, beginners find it difficult to learn how to actually use them in real application because the demos usually stick to just displaying the capabilities of that control. I decided to write a program which will not just demonstrate the functionality of the control but also how to make it work for you in your programs.

I will be focusing on the GfxListCtrl because my program is based around it. GfxListCtrl is written by Iuri Apollonio. CHyperLink and CSystemTray are written by Chris Maunder.

How do I use the Textcall back function ?

Well, first of all I create a class called CPerson. This class holds all the details about the person and the Serialize function is overloaded to save and load the details.

An array is created to hold the CPerson objects as in CAddressDoc as

CArray<CPerson,CPerson&> m_PersonArray;

This makes it easy to use the TextCallBack function. Your TextCallBack function for the GfxListCtrl is declared as

void GetTextCallback(int iIndex, int iSubItem, long lCode, CString &cs)

where lCode gives which item in the array is required. iIndex and iSubItem gives you the row and column respectively on the screen. To get the actual column you will have to use GetColumnIndex() member function of the GfxListControl, which means in your view class you would write something like this

void CAddressView::GetTextCallback(int iIndex, int iSubItem, long lCode, CString &cs)
   int rc = wndList.GetColumnIndex(iSubItem);          // wndList is the GfxListControl
   CPerson person;
   cs = "";
   if (GetDocument()->m_PersonArray.GetSize() == 0 || 
   GetDocument()->m_PersonArray.GetSize() < (iIndex + 1)) {
   person = GetDocument()->m_PersonArray[lCode - 1 ];
   switch (rc) {
     case 0: cs.Format("%d", iIndex + 1 ); break;
     case ADDR_FIRST_NAME: cs = person.m_strFirstName;  break;
     case ADDR_LAST_NAME:  cs = person.m_strLastName;   break;
     case ADDR_MIDDLE_NAME:cs = person.m_strMiddleName; break;
     case ADDR_NAME:       cs = person.m_strName;       break;
     case ADDR_NICK_NAME:  cs = person.m_strNickName;   break;
     case ADDR_EMAIL:      cs = person.m_strEMail;      break;
     default:  cs.Format("%d, %d", lCode, rc);

For the AutoPreview alone you have to draw the text you want on to the screen in the function

long CAddressView::GetExInfoCallback(LXHDREX * pLx)


      LXHDREX_DIV * pLxEx = (LXHDREX_DIV *) pLx;
      COLORREF ocr = pLxEx->pDC->SetTextColor(RGB(0,0,255));
      pLxEx->pDC->DrawText(GetDocument()->m_PersonArray[pLx->dwItemData - 1].m_strNotes , 
             pLxEx->rcItem, DT_END_ELLIPSIS|DT_WORDBREAK);
      return 1;

where m_PersonArray[Index].strNotes is the text I want it to display.

How to solve the double click problem of GfxListCtrl when tooltip is displayed ?

To solve the double click problem just make the following changes to the class CGfxListTip.

Add the style CS_DBLCLKS to the WNDCLASS as

   WNDCLASS wndcls;
   HINSTANCE hInst = AfxGetInstanceHandle();
   if(!(::GetClassInfo(hInst, GFXLISTTIP_CLASSNAME, &wndcls)))
   { = CS_DBLCLKS | CS_SAVEBITS ; // Xavier added CS_DBLCLKS 
     wndcls.lpfnWndProc = AfxWndProc;          // Xavier changed from ::DefWindowProc;
     wndcls.cbClsExtra = wndcls.cbWndExtra = 0;

and add the line


to the function

BOOL CGfxListTip::PreTranslateMessage(MSG* pMsg)
BOOL CGfxListTip::PreTranslateMessage(MSG* pMsg)
   CWnd *pWnd;
   int hittest;

     case WM_LBUTTONDBLCLK:         // Xavier added
     POINTS pts = MAKEPOINTS(pMsg->lParam);
     POINT  point;
     point.x = pts.x;

To use double click features in your program derive a class from GfxListCtrl. In my program that class is CAddressCtrl.

You have to override the OnLButtonDblClk(UINT nFlags, CPoint point) member function. Pass the point to CGfxListCtrl::HitTestEx(CPoint & point, int * col) member function and it will return to you the physical row and column on the screen at which the double click occurred. You can use the GetItemTextEx(index,column,cs) function where cs is a CString object to get the text of that Item. If you need to know the actual column on which the double click occurred like I do then you will have to use

column = pManager->FindColumnById(GetColumnIndex(column));

Based on this you can take the required action. In my program if you double click on the phone number it dials that number or double clicking on the URL will take you there. Here is the code

void CAddressCtrl::OnLButtonDblClk(UINT nFlags, CPoint point)
   if( GetFocus() != this ) SetFocus();
   int index, column;
   if ((index = HitTestEx(point, &column)) != -1) {
   if (column > 0 )  {
      CString cs;
      CString strURL;
      CString strName;
      CString strComment;
      if (pManager) {
         column = pManager->FindColumnById(GetColumnIndex(column));
      switch (column) {
        case ADDR_EMAIL: 
          if (!cs.IsEmpty()) {
          if (!cs.IsEmpty()) {
            if (strncmp((LPCTSTR) cs, "http://",7)==0)
            else {
     case ADDR_HOME_PHONE:
         if (!cs.IsEmpty()) {
            if ( column == ADDR_BUSINESS_PHONE)
               strComment = "Business Number";
               strComment = "Home Number";
            if (tapiRequestMakeCall(cs,"Address",strName, strComment)!=0) {
              AfxMessageBox("Unable to dial the number");
   CGfxListCtrl::OnLButtonDblClk(nFlags, point);

I modified the Chris Maunder class CHyperLink and made the GotoURL and GetRegKey member functions as static so that they can be called directly without the need to create an instance of the class. tapiRequestMakeCall is the TAPI function to make a call. If you want to use it in your project just include <tapi.h> and TAPI32.LIB into your project.

Serializations of the Template class CArray

To load and save my address array I serialized the CArray derived class as follows

template <> 
void AFXAPI SerializeElements <CPerson> ( CArchive& ar, CPerson* pNewPersons, int nCount ) {
   for ( int i = 0; i < nCount; i++, pNewPersons++ )    {
       // Serialize each CPerson object
       pNewPersons->Serialize( ar );
which makes the serialization of my CDocument class as simple as
void CAddressDoc::Serialize(CArchive& ar)

You can start the address book program with /tray as a command line parameter to tray it as it starts up.

If you like this program please let me know. If you want anymore details ask me I will it try to add it to this page.

Wishing you all the best with Visual C++

Xavier John

Download source - 139 Kb


  • How can chang the text color when I right-click a row,

    Posted by Legacy on 08/22/2002 12:00am

    Originally posted by: ChaoguangLiu

    How can I change the color of text: when I right-click a row ,I want to change the text color in the row ,how can I do?

  • Address book build error

    Posted by Legacy on 03/28/2002 12:00am

    Originally posted by: Jorge Santos

    When I tryed to built the project, I've got this error:

    D:\Projectos\Address1\MainFrm.cpp(85) : error C2039: 'SetExtendedStyle' : is not a member of 'CToolBarCtrl'
    D:\Projectos\Address1\MainFrm.cpp(85) : error C2065: 'TBSTYLE_EX_DRAWDDARROWS' : undeclared identifier


  • CHyperLink Memory Leak

    Posted by Legacy on 08/07/2000 12:00am

    Originally posted by: Josee Oliviero

    The CHyperLink class used here and other with other applications written by Chris M. requires an additional 2-lines of code in the destructor to get rid of a memory leak.

    other code

    //if allocated, fee memory

  • A small bug in class CAddressView in VC5

    Posted by Legacy on 03/26/1999 12:00am

    Originally posted by: Gilberto Botaro

    The follow implementation cause a error in Notes preview for Address.exe:

    void CAddressView::OnUpdateAutopreview(CCmdUI* pCmdUI)
    pCmdUI->Enable(wndList.GetCategoryManager() == NULL);

    I replace with the follow and a error stop:

    void CAddressView::OnUpdateAutopreview(CCmdUI* pCmdUI)
    int oah = wndList.GetAutoPreviewHeight();
    if (oah <= 0)
    pCmdUI->Enable(wndList.GetCategoryManager() == NULL);


  • can not link with vc6.0

    Posted by Legacy on 03/25/1999 12:00am

    Originally posted by: curbstone

    LINK : fatal error LNK1104: cannot open file "..\..\Program Files\Microsoft Visual Studio\VC98\Lib\TAPI32.LIB"
    i have copy TAPI32.lib to above dirctory.but the error still exists.why?

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Hybrid cloud platforms need to think in terms of sweet spots when it comes to application platform interface (API) integration. Cloud Velocity has taken a unique approach to tight integration with the API sweet spot; enough to support the agility of physical and virtual apps, including multi-tier environments and databases, while reducing capital and operating costs. Read this case study to learn how a global-level Fortune 1000 company was able to deploy an entire 6+ TB Oracle eCommerce stack in Amazon Web …

  • Event Date: April 15, 2014 The ability to effectively set sales goals, assign quotas and territories, bring new people on board and quickly make adjustments to the sales force is often crucial to success--and to the field experience! But for sales operations leaders, managing the administrative processes, systems, data and various departments to get it all right can often be difficult, inefficient and manually intensive. Register for this webinar and learn how you can: Align sales goals, quotas and …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds