Using the WTL CListBox class

Working with Win32 listbox controls is fairly simple but the code can be quite convoluted and get tedious after a while. I decided to use the WTL library to simplify some listbox handling code but it wasn't initially obvious how to do this. Hopefully this blog post will help someone else understand the basics.

Manual message processing

The majority of Win32 pro­gram­ming involves working with messages of various types that are basically #defines in header files. The Listbox control responds to messages like these:
  • LB_GETCURSEL (get the selected item)
  • LB_DELETESTRING (delete a string)
  • LB_IN­SERT­STRING (add a string)

..but you also have to make sure you use the correct WPARAM and LPARAMs.

The resulting code for adding an item to a Listbox looks like this:

TCHAR szBuffer[80] = {0};
UINT chars = GetDlgItemText(IDC_EDIT1, szBuffer, 80);
SendDlgItemMessage(IDC_LIST1, LB_INSERTSTRING, (WPARAM) 0, (LPARAM)szBuffer);

As you can see this requires a lot of work that I’ve grown tired of with years of C# coding.

Sim­pli­fy­ing with WTL

It is best to thinking of sim­pli­fi­ca­tion here with a view to the long term. You are writing C++ so this is not as straight­for­ward as WinForms or WPF.

First of all you need to create a member variable in your window class. I'm assuming you have installed the WTL AppWizard into Visual Studio and have created a Dialog ap­pli­ca­tion, but the steps are similar for other types of window. The code looks something like this:

class CMainDlg : public CDialogImpl<CMainDlg>, public CUpdateUI<CMainDlg>, public CMessageFilter, public CIdleHandler
    CListBox m_ListBox;
    enum { IDD = IDD_MAINDLG };

As you can see we have private called m_ListBox that we can reference elsewhere. Next an instance of CListBox needs to be attached to a Listbox that has been added to your dialog resource file. You do this in the OnInit­Di­a­log() method:

LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)

The IDC_LIST1 parameter is the name defined in my resource file and messages are now being routed between the instance variable and the actual control.

Now in the event handling code it is possible to call the AddString() method without having to worry about message types:

LRESULT OnAddItem(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
    TCHAR szBuffer[80] = {0};
    UINT chars = GetDlgItemText(IDC_EDIT1, szBuffer, 80);
    return 0;

This is a rather naïve example as I’m not taking advantage of WTL for the Edit control, but that’ll be the subject of a future blog post.

Tagged with c, win32, windows and wtl.