Win32 Common Controls, Part 4: Header Windows and List View Windows

Nancy Winnick Cluts
Microsoft Developer Network Technology Group

April 1994

Revised: February 1995 (LVS_NOITEMDATA style deleted)
June 1995 (LVS_ALWAYSSEL removed; LVS_SHOWSELALWAYS added)

Click to open or copy the files in the ListView sample application for this technical article.

Abstract

The next release of the Microsoft® Windows® operating system (called Windows 95) presents a new set of common controls to developers of Windows-based applications. These controls are provided in a new dynamic-link library (DLL) called COMCTL32.DLL. The controls allow developers to integrate existing applications into the new Windows 95 shell more thoroughly and seamlessly. COMCTL32.DLL is included with Windows 95 and will also be supported in Win32s® (running on Windows version 3.1) and in Windows NT™. Note that these controls are 32-bit only—they will not be supported in 16-bit Windows environments.

This article describes two new common controls, header windows and list view windows, which are generally used together. It is the fourth in a series of articles introducing the new common controls. The other articles in the series cover the following topics:

Parts 2–6 of the series have associated code samples that demonstrate the use of the Win32® common controls.

Warning   The ListView executable file associated with this article was built and tested using the Windows 95 Preliminary Development Kit. The executable will run only on Windows 95; it will not run under Windows 3.1 or Windows NT. If you have Windows 95 installed on your machine, but you have problems running this sample, copy the project files to your system using the button above, rebuild the project, and run the executable.

Please note that this article is based on preliminary information that is subject to change before the final version of Windows 95.

Header Windows

A header window is a horizontal window usually positioned above columns of text or numbers, containing titles for each column. Microsoft® Mail and Microsoft Excel include examples of these controls. You can divide a header window into parts, called header items, and allow the user to set the width of each item. Items can behave like push buttons and do something (for example, sort data) when the user clicks them. Header items appear as text on a gray background. It is important to note that header windows do not support a keyboard interface, and, as a result, do not accept the input focus.

Header windows are generally used in conjunction with list view windows. You can see an example of a header window/list view window combination in the ListView sample that is associated with this article.

Each item in a header window can have a string, a bitmapped image, and an application-defined 32-bit value associated with it. The string and bitmap are displayed within the boundaries of the item. If an item contains both a string and an image, the image is displayed above the string. If the string and image overlap, the string overwrites the overlapping portion of the image. Figure 1 illustrates a typical header window with four header items.

Figure 1. A header window with four header items

Header Window Styles

Header windows can have different window styles that determine the appearance and behavior of the window. For example, if you include the HDS_DIVIDERTRACK window style, the user will be able to set the width of the items by dragging the divider between the items with the mouse. You set the initial styles when you create the header window. If you want to get the current styles or change the styles later, you can use the GetWindowLong and SetWindowLong functions. Table 1 lists the header window styles supported in the Microsoft Windows® 95 operating system.

Table 1. Header Window Styles

Style Use
HDS_BUTTONS Causes header items to act like push buttons. This style is useful if your application must do something (for example, sort a list) when the user clicks a header item.
HDS_DIVIDERTRACK Enables the user to use the divider area between header items to set the width of the items.
HDS_HIDDEN Hides the header window. (You may want to do this, for example, if you want to create the header window when launching your application, but fill in the text for header items later, or if you want to reuse the header window and dynamically change the associated text.)
HDS_HORZ Specifies a horizontal header window.

Header Window Behavior

Typically, you must set the size and position of a header window to fit within the boundaries of a particular rectangle, such as the client area of the parent window. The default position is (–100, –100); the default width and height are 10 device units each. You can query the system for the appropriate size and position by sending the HDM_LAYOUT message to the header window. When sending this message, you fill in the coordinates of the rectangle that the header window should occupy, and you pass a pointer to a WINDOWPOS structure. The header window fills in the WINDOWPOS structure with size and position values appropriate for positioning the window along the top of the specified rectangle. The height value is the sum of the width of the window's horizontal borders and the average height of characters in the font currently selected into the window's device context. If you want to use the HDM_LAYOUT message to set the initial size and position of a header window, you should set the initial visibility state of the window so that it is hidden (by specifying the HDS_HIDDEN style). Once you have created the window and used the HDM_LAYOUT message to get the size and position values, you can call the SetWindowPos function to set the new size, position, and visibility state.

Creating a Header Window

You can create a header window by calling the CreateWindow or CreateWindowEx function, and specifying WC_HEADER for the class name. You can use the following code to create a header window and position it along the top of its parent window's client area. The code uses the Header_Layout macro (which sends the HDM_LAYOUT message) to get the appropriate size and position for the header window, given the bounding rectangle of the parent window's client area. The CreateHeaderWindow function returns the handle of the newly created header window. If the header window cannot be created, the function returns NULL.

HWND CreateHeaderWindow(HWND hwndParent)
{
   HWND hwndHeader;
   RECT rcParent;
   HD_LAYOUT hdl;
   WINDOWPOS wp;

   if ((hwndHeader = CreateWindowEx(
      0L,             // No extended styles.
      WC_HEADER,      // A header class window.
      (LPCTSTR) NULL, // No default text.
      WS_CHILD | WS_BORDER | HDS_BUTTONS | HDS_HORZ | HDS_DIVIDERTRACK, 
      0, 0, 0, 0,     // No size or position.
      hwndParent,         // Handle to the parent window.
      (HMENU) ID_HEADER,  // ID for the header window.
      hInst,              // Current instance.
      (LPVOID) NULL)) == NULL) // No application-defined data.

      return (HWND) NULL;

   // Get the bounding rectangle of the parent window's client area.
   GetClientRect(hwndParent, &rcParent);

   hdl.prc = &rcParent;
   hdl.pwpos = ℘
   // Call the Header_Layout macro to get the appropriate size
   // for the window.
   if (Header_Layout (hwndHeader, &hdl) == FALSE)
      return (HWND) NULL;

   // Set the size, position, and visibility of the header window.
   SetWindowPos(hwndHeader, wp.hwndInsertAfter, wp.x, wp.y,
         wp.cx, wp.cy, wp.flags | SWP_SHOWWINDOW);

   return hwndHeader;
}

Adding an Item to a Header Window

Now that the header window has been created, it is time to start adding items to it. (It would be pretty silly to have a header window with no items.) You can add an item to a header window by sending the HDM_INSERTITEM message to the window or by calling the Header_InsertItem macro. The HDM_INSERTITEM message includes the address of an HD_ITEM structure that defines the properties of the item, including its string, bitmap, initial size, and application-defined value. The structure also specifies formatting flags that tell the header window whether to center, left-justify, or right-justify the string or bitmap within the item's rectangle. The following code demonstrates how to add an item (string or bitmap) to a header window using the Header_InsertItem macro.

BOOL InsertItem(HWND hwndHeader, LPSTR lpsz, HBITMAP hBitmap)
{
   HD_ITEM hdi;  // Header item.

   // The .fmt member is valid and the .cxy member specifies the width.
   hdi.mask = HDI_FORMAT | HDI_WIDTH; 
   hdi.fmt = HDF_LEFT;  // Left-justify the item.

   if (lpsz)  // It is a string.
   {
      hdi.mask |= HDI_TEXT;   // The .pszText member is valid.
      hdi.pszText = lpsz;     // The text for the item.
      hdi.cxy = 75;           // The initial width.
      hdi.cchTextMax = lstrlen(hdi.pszText);  // The length of the string.
      hdi.fmt |= HDF_STRING;  // This item is a string.
   }
   if (hBitmap)
   {
      hdi.mask |= HDI_BITMAP; // The .hbm member is valid.
      hdi.cxy = 32;           // The initial width.
      hdi.hbm = hBitmap;      // The handle to the bitmap.
      hdi.fmt |= HDF_BITMAP;  // This item is a bitmap.
   }

   // Insert the item at the current index.
   if (Header_InsertItem(hwndHeader, CurrIndex, &hdi) == TRUE)
   {
      CurrIndex++;  // Increment the index.
      return TRUE;
   }
   return FALSE;
}

Header Window Messages

An application sends messages to header windows as it would to any other window, to change the behavior and appearance of the window. For example, you can add items, delete items, or change the text of an item by sending the appropriate message. Each message has a corresponding macro that you can send to a header window. This section lists header window messages, the corresponding macros, return values, and parameters. The hwndHD parameter for each macro is the handle to the header window. In many cases, wParam and lParam are zero and not used. The structures mentioned in the descriptions below are described in the next section, "Header Window Structures."

HDM_DELETEITEM

wParam = i;                       \\ index of the item to delete
lParam = 0;                       \\ not used

Description: The HDM_DELETEITEM message deletes an item from a header window.

Parameters: wParam (int i) is the index of the item to delete. lParam is not used.

Return value: TRUE if successful; FALSE otherwise.

Macro: BOOL Header_DeleteItem(hwndHD, i);

HDM_GETITEM

wParam = i;                      \\ index of the item
lParam = (HD_ITEM *)phdi;        \\ buffer receiving the item information

Description: The HDM_GETITEM message gets information about an item in a header window.

Parameters: wParam (int i) is the index of the item for which information is requested. lParam (HD_ITEM * phdi) is the address of an HD_ITEM structure. The mask member of the HD_ITEM structure indicates the type of information being requested. The other members of the structure are filled in based on the requested information. If mask is zero, the message returns TRUE, but copies no information to the HD_ITEM structure.

Return value: TRUE if successful; FALSE otherwise.

Macro: BOOL Header_GetItem(hwndHD, i, phdi);

HDM_GETITEMCOUNT

wParam = 0;                       \\ not used
lParam = 0;                       \\ not used

Description: The HDM_GETITEMCOUNT message gets a count of the items in a header window.

Parameters: wParam and lParam are not used.

Return value: The number of items if successful; –1 otherwise.

Macro: int Header_GetItemCount(hwndHD);

HDM_INSERTITEM

wParam = i;                     \\ index of the item after which to insert 
lParam = (HD_ITEM *)phdi;       \\ structure containing item information

Description: The HDM_INSERTITEM message inserts a new item within a header window.

Parameters: wParam (int i) is the index of the item after which the new item is to be inserted. The new item is inserted at the end of the header window if i is greater than or equal to the number of items in the window. lParam (HD_ITEM * phdi) is the address of an HD_ITEM structure that contains information about the new item.

Return value: The index of the new item if successful; –1 otherwise.

Macro: int Header_InsertItem(hwndHD, i, phdi);

HDM_LAYOUT

wParam = 0;                       \\ not used
lParam = (HD_LAYOUT *)playout;    \\ structure containing layout information

Description: The HDM_LAYOUT message gets the size and position of a header within a given rectangle. This message is used to determine the dimensions of a new header window, given the bounding rectangle specified in the prc member of the HD_LAYOUT structure.

Parameters: wParam is not used. lParam (HD_LAYOUT * playout) is the address of an HD_LAYOUT structure. In HD_LAYOUT, the prc member specifies the coordinates of a rectangle, and the pwpos member is filled in with the size and position of the header window within the given rectangle.

Return value: TRUE if successful; FALSE otherwise.

Macro: BOOL Header_Layout(hwndHD, playout);

HDM_SETITEM

wParam = i;                       \\ index of the item to be set
lParam = (HD_ITEM *)phdi;         \\ structure containing item information

Description: The HDM_SETITEM message sets the attributes of the specified item in a header window. The HDN_ITEMCHANGING notification is sent to the parent window before the item attributes are changed. The parent window can return FALSE to prevent the changes, in which case HDM_SETITEM returns FALSE. If the parent window returns TRUE, the changes are made and the parent window receives an HDN_ITEMCHANGED notification.

Parameters: wParam (int i) is the index of the item whose attributes are to be changed. lParam (HD_ITEM * phdi) is the address of an HD_ITEM structure. The mask member of the HD_ITEM structure indicates the attributes to set. The other members of the structure specify the new attributes.

Return value: TRUE if successful; FALSE otherwise.

Macro: BOOL Header_SetItem(hwndHD, i, phdi);

Header Window Structures

This section lists the new structures in Windows 95 that support header windows. An application may need to use these structures whenever it sends a message or notification to a header window.

HD_ITEM

typedef struct _HD_ITEM {
    UINT mask;      \\ mask flags, as described below
    int cxy;        \\ width and height of the item
    LPSTR pszText;  \\ the item string
    HBITMAP hbm;    \\ handle of the item bitmap
    int cchText;    \\ length of the item string, in characters
    int fmt;        \\ format flags, as described below
    LPARAM lParam;  \\ application-defined data
} HD_ITEM;

The HD_ITEM structure contains information about an item in a header window. You fill in this structure whenever you add an item to the header window. You can also get this information by using the Header_GetItem macro. The HD_ITEM structure has the following members:

HD_LAYOUT

typedef struct _HD_LAYOUT {
    RECT FAR *prc;         \\ bounding rectangle coordinates
    WINDOWPOS FAR *pwpos;  \\ appropriate size for the header window
} HD_LAYOUT;

The HD_LAYOUT structure contains information for setting the size and position of a header window. This structure is used with the HDM_LAYOUT message and contains the following members:

HD_NOTIFY

typedef struct _HD_NOTIFY {
    NMHDR hdr;        \\ common control notification structure
    int iItem;        \\ index of the item
    int iButton;      \\ index of the mouse button
    HD_ITEM *pitem;   \\ item information
} HD_NOTIFY;

The HD_NOTIFY structure contains information used to process notification messages from a header window. This structure contains the following members:

Header Window Notification Messages

Table 2 lists the notification messages that Windows sends to header windows. The parent window of the header window receives these messages via a WM_NOTIFY message. For each notification, the lParam is a FAR pointer to an HD_NOTIFY structure (described in the previous section).

Table 2. Header Window Notification Messages

Message Description
HDN_BEGINTRACK Sent when the user begins dragging a divider in the window (the user has pressed the left mouse button while the mouse cursor is over a divider in the header window). The parent window may return FALSE to allow tracking of the divider, or TRUE to prevent tracking.
HDN_ENDTRACK Sent when the user finishes dragging a divider.
HDN_ITEMCHANGED Sent when the attributes of a header item have changed.
HDN_ITEMCHANGING Sent when the attributes of a header item are about to change. The parent window may return FALSE to allow the changes, or TRUE to prevent them.
HDN_ITEMCLICK Sent when the user clicks the header window. A header window sends this notification after the user releases the left mouse button. A window that has the HDS_DIVIDERTRACK style does not send this notification when the user clicks the divider.
HDN_TRACK Sent when the user drags a divider in the header window. The parent window may return FALSE to continue tracking the divider, or TRUE to end tracking.

List View Windows

A list view window displays a collection of items such as files or folders. The user or an application can manipulate these items in a variety of ways, for example, they can drag the items or sort them by clicking the column headings. Any number of subitems can be associated with each item, but all items must have the same number of subitems. A subitem contains a text string that appears next to the item in report view.

A list view window can be viewed in four different ways (views): using their large (or standard) icons, using their small icons, as a list, or as a report. The current view is specified by two window style bits that you can set with the SetWindowStyle function.

In standard icon view, each item is represented by a full-sized icon and a text label. The user can drag items to any location in the list view window. A list view window in standard icon view (illustrated in Figure 2) resembles a program group in the Windows 3.1 Program Manager.

Figure 2. A list view window in standard icon view

In small icon view, each item is represented by a small icon and text to the right of the icon, thus saving screen real estate. As in standard icon view, the user can drag the items to any location in the window. Figure 3 shows a list view window in small icon view. To avoid truncating the labels, you can reset the length of the displayed text in your program.

Figure 3. A list view window in small icon view

List view also uses the small icon and the text label to the right of the icon, but the items are arranged in columns and cannot be dragged by the user (Figure 4).

Figure 4. A list view window in list view

In report view, you can display the items with their small icons and labels, and you can provide additional information about each item. Each item appears on its own line, with information arranged in columns. The leftmost column contains the icon, followed by the text label. Additional columns display the text for each of the item's subitems. Optionally, you can use a header window to show the title of each column. In Figure 5, if the user clicks one of the column headings, the list is sorted based on the sort criterion specified for that column. For example, clicking the Bedrooms heading sorts the data by the number of bedrooms.

Figure 5. A list view window in report view

List View Window Styles and States

You can specify different window styles when you create a list view window to determine the appearance and behavior of the window. You set the initial styles when you create the list view window with the CreateWindow or CreateWindowEx function. Table 3 lists the window styles that Windows 95 supports for list view windows.

Table 3. List View Window Styles

Style Use
LVS_ICON, LVS_SMALLICON, LVS_LIST, or
LVS_REPORT
Specifies the current view for the window: standard icon, small icon, list, or report.
LVS_SINGLESEL Allows the user to select only one item at a time from the list view window. By default, the user may select multiple items.
LVS_SHOWSELALWAYS Specifies that the selection (if any) should always be shown, even if the list view does not have the focus.
LVS_SORTASCENDING or LVS_SORTDESCENDING Sorts items based on their text labels. Items can be sorted either in ascending or descending order.
LVS_SHAREIMAGELISTS Prevents image lists from being created when the window is created, or destroyed when the window is destroyed.
LVS_NOLABELWRAP Displays text labels on a single line in icon view. By default, text labels may wrap in icon view.
LVS_AUTOARRANGE Automatically arranges icons in standard icon view and small icon view.
LVS_EDITLABELS Allows the user to edit text labels in place.
LVS_ALIGNLEFT, LVS_ALIGNRIGHT, LVS_ALIGNBOTTOM, or LVS_ALIGNTOP Specifies the alignment of items within the list view window. These flags only apply to standard icon and small icon view.
LVS_NOCOLUMNHEADER Specifies that there is no column header. This style is valid for report view only.
LVS_NOSCROLL Disables scrolling. No item is allowed outside of the client area.
LVS_STATEIMAGES Indicates that there is a user-defined state for the images. This style uses the state image list.

Use the SetWindowStyle function to set some or all of the window styles for a list view window, and to notify the list view window that its style is changing. This function sends the WM_STYLECHANGING and WM_STYLECHANGED messages to the list view window. The mask parameter of SetWindowStyle can be one of the following:

Each item in a list view window has a current state (for example, selected or marked). These states are updated in response to a user's actions or when they are changed explicitly in the code. By default, the list view window maintains the state of each list item. However, you can specify that the list view notify the parent window (using the LVN_GETDISPINFO notification) whenever it needs to determine the state of an item via a callback. Table 4 lists the different states allowed for items.

Table 4. List View Item States

Value Meaning
LVIS_SELECTED The item is selected. The appearance of a selected item depends on whether it has the focus and on the system colors used for selection.
LVIS_FOCUSED The item has the focus and is surrounded by a standard focus rectangle. Although more than one item may be selected, only one item can have the focus.
LVIS_CUT The item is checked.
LVIS_DISABLED The item is disabled and is drawn using the standard disabled style and coloring.
LVIS_HIDDEN The item is not visible and does not respond to user interaction.
LVIS_DROPHILITED The item is highlighted as a drag-and-drop target.
LVIS_LINK The item is a link and is drawn accordingly.
LIVS_OVERLAYMASK The item is used as an image list overlay image.
LVIS_USERMASK The item uses client bits for state image drawing.

Creating a List View Window

Creating a list view window may appear to be a daunting task at first. Getting all of the information placed in the correct structures involves several steps:

  1. Create the window using CreateWindow or CreateWindowEx, specifying WC_LISTVIEW for the class name.

  2. Create image lists for the large and small icon views. Load the bitmaps for the images and add them to the image list. For more information on image lists, please see the next article in this series, entitled "Win32 Common Controls, Part Five: Image Lists and Tree View Windows," in the MSDN Library.

  3. Initialize the column headings you will use by loading the strings and calling ListView_InsertColumn.

  4. Insert each item into the list view and initialize any associated text.

The following code demonstrates these steps. For my sample, I created a real-estate listing. A structure that I defined contains information about the houses listed, including address, city, price, number of bedrooms, and number of bathrooms. I created an icon for each city represented (three icons total).

// House structure used for listing.
typedef struct tagHOUSEINFO {
   char szAddress[MAX_ADDRESS];
   char szCity[MAX_CITY];
   int iPrice;
   int iBeds;
   int iBaths;
} HOUSEINFO;

// Function that creates the list view window.
HWND CreateListView (HWND hWndParent)                                     
{
   HWND hWndList;      // Handle to the list view window.
   RECT rcl;           // Rectangle for setting the size of the window.
   HICON hIcon;        // Handle to an icon.
   int index;          // Index used in for loops.
   HIMAGELIST hSmall, hLarge; // Handles to image lists for large and small     
                              // icons.
   LV_COLUMN lvC;      // List view column structure.
   char szText[64];    // place to store some text.
   LV_ITEM lvI;        // List view item structure.
   int iSubItem;       // Index for inserting subitems.

   // Ensure that the common window DLL is loaded.
   InitCommonControls();

   // Get the size and position of the parent window.
   GetClientRect(hWndParent, &rcl);

   // Create the list view window.
   hWndList = CreateWindowEx( 0L,
      WC_LISTVIEW,                // List view class.
      "",                         // No default text.
      WS_VISIBLE | WS_CHILD | WS_BORDER | LVS_REPORT, // Window styles.
      0, 0,                       // Default x and y position.
      rcl.right - rcl.left, rcl.bottom - rcl.top, // Width and height of window.
      HWndParent,                 // Parent window.
      (HMENU) ID_LISTVIEW,        // Window ID.
      HInst,                      // Current instance.
      NULL );                     // No application-defined data.

   if (hWndList == NULL )
      return NULL;

   // Initialize the list view window.
   // First, initialize the image lists we will need
   // to create an image list for the small icons.
   hSmall = ImageList_Create ( BITMAP_WIDTH, BITMAP_HEIGHT, FALSE, 3, 0 );

   // Create an image list for the large icons.
   hLarge = ImageList_Create (BITMAP_WIDTH, BITMAP_HEIGHT, FALSE, 3, 0 )

   // Load the icons and add them to the image lists.
   for (index = REDMOND; index <= SEATTLE ; index++)
   {
      hIcon = LoadIcon ( hInst, MAKEINTRESOURCE(index));
      // There are 3 of each icon type, so add 3 at a time.
      for (iSubItem = 0; iSubItem < 3; iSubItem++)
      {
         if ((ImageList_AddIcon(hSmall, hIcon) == -1) ||
            (ImageList_AddIcon(hLarge, hIcon) == -1))
            return NULL;
      }
   }

   // Make sure that all of the icons are in the lists.
   if (ImageList_GetImageCount(hSmall) < 3)
      return FALSE;
   if (ImageList_GetImageCount(hLarge) < 3)
      return FALSE;
   // Associate lists with list view window.
   ListView_SetImageList(hWndList, hSmall, LVSIL_SMALL);
   ListView_SetImageList(hWndList, hLarge, LVS1L_NORMAL);

   // Now initialize the columns we will need.
   // Initialize the LV_COLUMN structure.
   // The mask specifies that the .fmt, .ex, width, and .subitem members 
   // of the structure are valid.
   lvC.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
   lvC.fmt = LVCFMT_LEFT;  // Left-align the column.
   lvC.cx = 75;            // Width of the column, in pixels.
   lvC.pszText = szText;   // The text for the column.

   // Add the columns. They are loaded from a string table.
   for (index = 0; index <= NUM_COLUMNS; index++)
   {
      lvC.iSubItem = index;
      LoadString( hInst, 
               IDS_ADDRESS + index,
               szText,
               sizeof(szText));
      if (ListView_InsertColumn(hWndList, index, &lvC) == -1)
         return NULL;
   }

   // Finally, let's add the actual items to the window.
   // Fill in the LV_ITEM structure for each of the items to add
   // to the list.
   // The mask specifies that the .pszText, .iImage, .lParam and .state
   // members of the LV_ITEM structure are valid.
   lvI.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM | LVIF_STATE;
   lvI.state = 0;      
   lvI.stateMask = 0;  

   for (index = 0; index < NUM_ITEMS; index++)
   {
      lvI.iItem = index;
      lvI.iSubItem = 0;
      // The parent window is responsible for storing the text. The list view
      // window will send an LVN_GETDISPINFO when it needs the text to display.
      lvI.pszText = LPSTR_TEXTCALLBACK; 
      lvI.cchTextMax = MAX_ITEMLEN;
      lvI.iImage = index;
      lvI.lParam = (LPARAM)&rgHouseInfo[index];

      if (ListView_InsertItem(hWndList, &lvI) == -1)
         return NULL;

      for (iSubItem = 1; iSubItem < NUM_COLUMNS; iSubItem++)
      {
         ListView_SetItemText( hWndList,
            index,
            iSubItem,
            LPSTR_TEXTCALLBACK);
      }
   }
   return (hWndList);
}

To see how the code above behaves, click to open the ListView project files and run LISTVIEW.EXE.

Warning   The ListView executable file was built and tested using the Windows 95 Preliminary Development Kit. The executable will run only on Windows 95; it will not run under Windows 3.1 or Windows NT. If you have Windows 95 installed on your computer but you have problems running this sample, copy the project files to your system, rebuild the project, and run the executable.

Handling the WM_NOTIFY Message in a List View Window

Once you have created a list view window, you need some way to handle the WM_NOTIFY messages that will be sent to the parent window. The following code is an implementation of a handler that I set up to do this. When the parent window receives the WM_NOTIFY notification, it calls this function to see whether it needs text for a list view item and whether it is necessary to sort the items. I am only interested in two of the notifications: the LVN_GETDISPINFO notification, which is sent when the system needs text supplied for a list view item, and the LVN_COLUMNCLICK notification, which is sent whenever the user clicks a column heading.

LRESULT NotifyHandler( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
   LV_DISPINFO *pLvdi = (LV_DISPINFO *)lParam;
   NM_LISTVIEW *pNm = (NM_LISTVIEW *)lParam;
   HOUSEINFO *pHouse = (HOUSEINFO *)(pLvdi->item.lParam);
   static char szText[10];

   if (wParam != ID_LISTVIEW)
      return 0L;

   switch(pLvdi->hdr.code)
   {
      case LVN_GETDISPINFO:
         // Display the appropriate item, getting the text or number
         // from the HOUSEINFO structure I set up.
         switch (pLvdi->item.iSubItem)
         {
            case 0:     // Address
               pLvdi->item.pszText = pHouse->szAddress;
               break;

            case 1:     // City
               pLvdi->item.pszText = pHouse->szCity;
               break;

            case 2:     // Price
               wsprintf(szText, "$%u", pHouse->iPrice);
               pLvdi->item.pszText = szText;
               break;

            case 3:     // Number of bedrooms
               wsprintf(szText, "%u", pHouse->iBeds);
               pLvdi->item.pszText = szText;
               break;

            case 4:     // Number of bathrooms
               wsprintf(szText, "%u", pHouse->iBaths);
               pLvdi->item.pszText = szText;
               break;

            default:
               break;
         }
         break;

      case LVN_COLUMNCLICK:
         // The user clicked one of the column headings. Sort by
         // this column. This function calls an application-defined
         // comparison callback function, ListViewCompareProc. The 
         // code for the comparison procedure is listed in the next section.
         ListView_SortItems( pNm->hdr.hwndFrom,
                        ListViewCompareProc,
                        (LPARAM)(pNm->iSubItem));
         break;

      default:
         break;
   }
   return 0L;
}

Sorting Items in Response to a Column Heading Click

Our list view window is now almost fully functional. The only thing left to implement is the code to sort the list view items when the user clicks a column heading. The list view window does not sort the items for you. (Drats!) This makes some sense—how would the system know which criterion you wanted to sort on (for example, color or size)? However, I would have liked to see Windows 95 provide some built-in sorting callbacks for "standard" sorting needs such as string comparisons and numeric sorts. (I guess I'll have to drop another suggestion in the big black box.) Because the list view window doesn't have this capability, you have to provide a callback function to do the sorting.

The following code demonstrates one method of sorting. It uses the lstrcmpi function to compare strings and simple arithmetic to sort the numbers. The lstrcmpi function compares two strings by checking the first character in the strings, the second character, the third character, and so on against each other until it reaches the end of the strings or it finds an inequality. The function returns the difference of the values of the first mismatched characters it encounters, for example, it determines that "abcz" is greater than "abcdefg" and returns the difference between z and d. For those of you who have localization concerns, the language (locale) selected by the user at setup time (or via the Control Panel) determines which string is greater (or whether the strings are the same). If no language (locale) is selected, Windows performs the comparison by using default values. This function can compare two double-byte character set (DBCS) strings in the DBCS version of Windows:

int CALLBACK ListViewCompareProc(LPARAM lParam1, LPARAM lParam2, LPARAM 
   lParamSort)
{
   HOUSEINFO *pHouse1 = (HOUSEINFO *)lParam1;
   HOUSEINFO *pHouse2 = (HOUSEINFO *)lParam2;
   LPSTR lpStr1, lpStr2;
   int iResult;

   if (pHouse1 && pHouse2)
   {
      switch( lParamSort)
      {
         case 0:     // Sort by address.
            lpStr1 = pHouse1->szAddress;
            lpStr2 = pHouse2->szAddress;
            iResult = lstrcmpi(lpStr1, lpStr2);
            break;

         case 1:     // Sort by city.
            lpStr1 = pHouse1->szCity;
            lpStr2 = pHouse2->szCity;
            iResult = lstrcmpi(lpStr1, lpStr2);
            break;

         case 2:     // Sort by price.
            iResult = pHouse1->iPrice - pHouse2->iPrice;
            break;

         case 3:     // Sort by the number of bedrooms.
            iResult = pHouse1->iBeds - pHouse2->iBeds;
            break;

         case 4:     // Sort by the number of bathrooms.
            iResult = pHouse1->iBaths - pHouse2->iBaths;
            break;

         default:
            iResult = 0;
            break;
      }
   }
   return(iResult);
}

List View Messages

This very long section lists the new messages you can use to manipulate list view windows. My suggestion is to skip to the next section, "List View Structures," and refer back to this section when you want to learn about specific functionality. Of course, if you love reading lists, this will be your favorite section. For the messages listed below, HWND hwndLV refers to the handle to the list view window unless otherwise noted. In many cases, wParam and/or lParam are zero and not used.

LVM_ARRANGE

wParam = UINT code;               \\ alignment and sort flag
lParam = 0;                       \\ not used

Description: The LVM_ARRANGE message arranges the items in icon view.

Parameters: wParam (UINT code) is the alignment and (optionally) the sort flag. The sort flag can be one of the values listed in Table 5 below. lParam is not used.

Table 5. List View Alignment Options

Value Meaning
LVA_DEFAULT Use the current alignment.
LVA_ALIGNLEFT Align along the left of the list window.
LVA_ALIGNTOP Align along the top of the list window.
LVA_ALIGNBOTTOM Align along the bottom of the list window.
LVA_ALIGNRIGHT Align along the right of the list window.
LVA_SNAPTOGRID Arrange the icons according to the closest grid position.
LVA_SORTASCENDING Sort in ascending order.
LVA_SORTDESCENDING Sort in descending order.

Return value: TRUE if successful; FALSE otherwise.

Macro: BOOL ListView_Arrange(HWND hwndLV, UINT code);

LVM_CREATEDRAGIMAGE

wParam = i;                       \\ index of the list view item
lParam = lpptUpLeft;              \\ not used

Description: The LVM_CREATEDRAGIMAGE message creates a drag image for the specified item.

Parameters: wParam (int i) is the index of the list view item. lParam (LPPOINT lpptUpLeft) is the address of a POINT structure that receives the initial location of the upper-left corner of the image, in view coordinates.

Return value: The handle to the image list created, or NULL if unsuccessful.

Macro: (HIMAGELIST)ListView_CreateDragImage(hwndLV, iItem, lpptUpLeft);

LVM_DELETEALLITEMS

wParam = 0;                       \\ not used
lParam = 0;                       \\ not used

Description: The LVM_DELETEALLITEMS message removes all items from a list view window.

Parameters: wParam and lParam are not used.

Return value: TRUE if successful; FALSE otherwise.

Macro: (BOOL)ListView_DeleteAllItems(hwndLV);

LVM_DELETECOLUMN

wParam = iCol;                    \\ index of the column to delete
lParam = 0;                       \\ not used

Description: The LVM_DELETECOLUMN message removes a column from a list view window.

Parameters: wParam (int iCol) is the index of the column to delete. lParam is not used.

Return value: TRUE if successful; FALSE otherwise.

Macro: (BOOL)ListView_DeleteColumn(hwndLV, iCol);

LVM_DELETEITEM

wParam = i;                       \\ index of the item to delete
lParam = 0;                       \\ not used

Description: The LVM_DELETEITEM message removes an item from a list view window.

Parameters: wParam (int i) is the index of the item to delete. lParam is not used.

Return value: TRUE if successful; FALSE otherwise.

Macro: (BOOL)ListView_DeleteItem(hwndLV, i);

LVM_EDITLABEL

wParam = i;                       \\ index of the item being edited
lParam = 0;                       \\ not used

Description: The LVM_EDITLABEL message begins in-place editing of an item's text. This message selects and sets the focus to the item. When the user completes or cancels editing, the edit window is destroyed and the handle becomes invalid. You can safely subclass the edit window, but do not destroy it. To cancel editing, you can send the list view a WM_CANCELMODE message.

Parameters: wParam (int i) is the index of the list view item being edited. lParam is not used.

Return value: If successful, the message returns the handle of the edit window used to edit the text. This will be NULL if the editing is unsuccessful.

Macro: (HWND)ListView_EditLabel(hwndLV, i);

LVM_ENSUREVISIBLE

wParam = i;                       \\ index of the item
lParam = (BOOL)fPartialOK;        \\ TRUE to prohibit scrolling

Description: The LVM_ENSUREVISIBLE message ensures that a list view item is entirely or partially visible by scrolling the list view window if necessary.

Parameters: wParam (int i) is the index of the list view item. If lParam (BOOL fPartialOK) is TRUE, no scrolling will occur if the item is at least partially visible. If FALSE, the item must be entirely visible.

Return value: TRUE if successful; FALSE otherwise.

Macro: (BOOL)ListView_EnsureVisible(hwndLV, I, fPartialOK);

LVM_FINDITEM

wParam = iStart;                  \\ index of item to start search
lParam = (LV_FINDINFO *)plvfi;    \\ structure specifying search criteria

Description: The LVM_FINDITEM message searches for a list view item.

Parameters: wParam (int iStart) is the index of the item at which the search will start. Specifying –1 will start the search at the beginning. lParam (LV_FINDINFO *plvfi) is the structure that specifies the search criteria.

Return value: If successful, the message returns an int indicating the index of the list view item. If unsuccessful, the message returns –1.

Macro: (int)ListView_FindItem(hwndLV, iStart, plvfi);

LVM_GETBKCOLOR

wParam = 0;                       \\ not used
lParam = 0;                       \\ not used

Description: The LVM_GETBKCOLOR message gets the background color of the list view window.

Parameters: wParam and lParam are not used.

Return value: The background color of the window (COLORREF).

Macro: (COLORREF) ListView_GetBkColor (hwndLV);

LVM_GETCALLBACKMASK

wParam = 0;                       \\ not used
lParam = 0;                       \\ not used

Description: The LVM_GETCALLBACKMASK message gets the callback mask for a list view window. For information about the callback mask, see Table 4, List View Item States, previously in this article.

Parameters: wParam and lParam are not used.

Return value: The callback mask (UINT).

Macro: (UINT)ListView_GetCallbackMask(hwndLV);

LVM_GETCOLUMN

wParam = iCol;                    \\ index of the column
lParam = (LV_COLUMN FAR *)pcol;   \\ structure that gets the column information

Description: The LVM_GETCOLUMN message gets the attributes of a list view column. The mask member of the LV_COLUMN structure passed in specifies which attributes to get. If the LVCF_TEXT flag is specified, the pszText member must contain the address of the buffer that receives the item text, and the cchTextMax member must specify the size of the buffer.

Parameters: wParam (int iCol) is the index of the column. lParam (LV_COLUMN FAR * pcol) is the structure to be filled in with column information.

Return value: TRUE if successful; FALSE otherwise.

Macro: (BOOL)ListView_GetColumn(hwndLV, iCol, pcol);

LVM_GETCOLUMNWIDTH

wParam = iCol;                    \\ index of the column
lParam = 0;                       \\ not used

Description: The LVM_GETCOLUMNWIDTH message gets the width of a column in list view or report view.

Parameters: wParam (int iCol) is the index of the column. This is ignored in list view. lParam is not used.

Return value: The column width if successful; zero otherwise.

Macro: (int)ListView_GetColumnWidth(hwndLV, iCol);

LVM_GETCOUNTPERPAGE

wParam = 0;                       \\ not used
lParam = 0;                       \\ not used

Description: The LVM_GETCOUNTPERPAGE message calculates the number of items that can fit vertically in the visible area of a view control in list view or report view.

Parameters: wParam and lParam are not used.

Return value: The number of items if successful. If the list view is currently in standard icon or small icon view, the return value is the total number of items in the list view.

Macro: (int)ListView_GetCountPerPage(hwndLV);

LVM_GETEDITCONTROL

wParam = 0;                       \\ not used
lParam = 0;                       \\ not used

Description: The LVM_GETEDITCONTROL message gets the handle of the edit window used to edit the item text in place. The edit window is destroyed and the handle becomes invalid when the user completes or cancels editing. You can safely subclass the edit window, but do not destroy it. To cancel editing, you can send the list view a WM_CANCELMODE message. The list view item being edited is the item that is currently in the focused state.

Parameters: wParam and lParam are not used.

Return value: The handle of the edit window if successful. If the message is unsuccessful or no label is currently being edited, the message returns NULL.

Macro: (HWND)ListView_GetEditControl(hwndLV);

LVM_GETIMAGELIST

wParam = (BOOL)fSmallImages;      \\ TRUE to get small icon list
lParam = 0;                       \\ not used

Description: The LVM_GETIMAGELIST message gets the handle of an image list used for drawing list view items.

Parameters: If wParam (int fSmallImages) is TRUE, the message returns a handle for the small icon image list; if FALSE, the message returns a handle for the standard icon image list. lParam is not used.

Return value: The handle of the specified image list if successful; NULL otherwise.

Macro: HIMAGELIST ListView_GetImageList(hwndLV, fSmallImages);

LVM_GETITEM

wParam = 0;                       \\ not used
lParam = (LV_ITEM FAR *)pitem;    \\ structure receiving item information

Description: The LVM_GETITEM message gets a list view item's attributes.

Parameters: wParam is not used. lParam (LV_ITEM FAR * pitem) is the item structure to fill in. The iItem and iSubItem members of the LV_ITEM structure identify the item or subitem on which to get information, and the mask member specifies the attributes to get. If the mask member specifies the LVIF_TEXT flag, the pszText member must contain the address of the buffer that receives the item text, and the cchTextMax member must specify the size of the buffer. If the mask member specifies the LVIF_STATE flag, the stateMask member specifies which item states are to be returned.

Return value: TRUE if successful; FALSE otherwise.

Macro: (BOOL)ListView_GetItem(hwndLV, pitem);

LVM_GETITEMCOUNT

wParam = 0;                       \\ not used
lParam = 0;                       \\ not used

Description: The LVM_GETITEMCOUNT message gets the number of items in a list view window.

Parameters: wParam and lParam are not used.

Return value: The number of items.

Macro: (int)ListView_GetItemCount(hwndLV);

LVM_GETITEMPOSITION

wParam = i;                       \\ index of the list view item
lParam = (POINT FAR *)ppt;        \\ position of the item

Description: The LVM_GETITEMPOSITION message gets the position of a list view item in standard icon and small icon views.

Parameters: wParam (int i) is the index of the list view item. lParam (POINT FAR* ppt) is the position of the item in the list view window's client coordinates.

Return value: TRUE if successful; FALSE otherwise.

Macro: (BOOL)ListView_GetItemPosition(hwndLV, I, ppt);

LVM_GETITEMRECT

wParam = i;                       \\ index of the item
lParam = (RECT FAR *)prc;         \\ bounding rectangle

Description: The LVM_GETITEMRECT message gets the bounding rectangle for an item in the current view.

Parameters: wParam (int i) is the index of the item. lParam (RECT FAR * prc) is the bounding rectangle. The int code member of the RECT structure specifies the portion of the list item for which you want to get the bounding rectangle. This can be one of the values listed in Table 6 below. The code portion is specified in the prc->left member of the RECT structure.

Table 6. List View Bounding Rectangle Options

Option Meaning
LVIR_BOUNDS Get the bounding rectangle for the entire item, including the icon and the label.
LVIR_ICON Get the bounding rectangle for the icon only.
LVIR_IMAGE Get the bounding rectangle for the icon, but exclude the icon margin.
LVIR_LABEL Get the bounding rectangle for the icon label.
LVIR_SELECTBOUNDS Set the bounding rectangle to include the icon and the item text in the label such that when the user clicks within the rectangle, the item is selected.

Return value: TRUE if successful; FALSE otherwise.

Macro: (BOOL)ListView_GetItemRect(hwndLV, i, prc, code);

LVM_GETITEMSTATE

wParam = i;                       \\ index of the item
lParam = UINT mask;               \\ flag indicating which state flags to get

Description: The LVM_GETITEMSTATE message gets the state of a list view item.

Parameters: wParam (int i) is the index of the item. lParam (UINT mask) specifies which state flags to get.

Return value: The item's state flags, as described in Table 4, List View Item States, previously in this article.

Macro: (UINT)ListView_GetItemState(hwndLV, i, mask);

LVM_GETITEMTEXT

wParam = i;                       \\ index of the item
lParam = (LV_ITEM FAR *)plvi;     \\ structure that receives the text

Description: The LVM_GETITEMTEXT message gets the item text of a list view item or subitem.

Parameters: wParam (int i) is the index of the item. lParam (LV_ITEM FAR * plvi) is the item structure. This structure should have the iSubItem member filled in (if you want to get the text for a subitem) and the maximum number of characters to get. You must fill in the following members of the LV_ITEM structure:

Return value: The length of the item text.

Macro: (int)ListView_GetItemText(hwndLV, i, iSubItem, pszText, cchTextMax);

LVM_GETNEXTITEM

wParam = iStart;                  \\ index of item to start at
lParam = UINT flags;              \\ relational flags

Description: The LVM_GETNEXTITEM message searches for the next list view item starting from a specified item. If an item does not have all of the specified state flags set, the search continues with the next item.

Parameters: wParam (int iStart) is the index of the item to start at, or –1 to start from the beginning. In lParam (UINT flags), flags specify the geometric relation of the requested item to the specified item and the state of the requested item. The geometric relation can be one of the values listed in Table 7 below. Note that the first five flags are mutually exclusive but can be used in combination with any of the remaining flags.

Table 7. List View Search Criteria

Value Meaning
LVNI_ALL Search for a subsequent item based on the index. This is the default.
LVNI_ABOVE Search for an item that is above the specified item.
LVNI_BELOW Search for an item that is below the specified item.
LVNI_TORIGHT Search for an item to the right of the specified item.
LVNI_TOLEFT Search for an item to the left of the specified item.
LVNI_FOCUSED Return focused items.
LVNI_SELECTED Return selected items.
LVNI_CUT Return marked items.
LVNI_HIDDEN Return hidden items.
LVNI_DROPHILITED Return the drop-highlighted items.
LVNI_PREVIOUS Search backwards.

Return value: The index of the next item if successful; –1 otherwise.

Macro: (int)ListView_GetNextItem(hwndLV, iStart, flags);

LVM_GETORIGIN

wParam = 0;                       \\ not used
lParam = (POINT FAR *)ppt;        \\ structure receiving origin values

Description: The LVM_GETORIGIN message gets the list view origin, which is needed for setting the item position.

Parameters: wParam is not used. lParam (POINT FAR * ppt) specifies a structure that receives the origin values.

Return value: TRUE if successful; FALSE otherwise.

Macro: (BOOL)ListView_GetOrigin(hwndLV, ppt);

LVM_GETSTRINGWIDTH

wParam = 0;                       \\ not used
lParam = (LPCSTR)psz;             \\ the string

Description: The LVM_GETSTRINGWIDTH message gets the minimum column width necessary to display the given string. The returned width takes the current font and column margins of the list view into account, but does not take the width of a small icon into account.

Parameters: wParam is not used. lParam (LPCSTR psz) specifies the string.

Return value: The column width if successful; 0 otherwise.

Macro: (int)ListView_GetStringWidth(hwndLV, psz);

LVM_GETTEXTBKCOLOR

wParam = 0;                       \\ not used
lParam = 0;                       \\ not used

Description: The LVM_GETTEXTPKCOLOR message gets the background text color in a list view window.

Parameters: wParam and lParam are not used.

Return value: The background color of the text (COLORREF).

Macro: (COLORREF)ListView_GetTextBkColor(hwndLV);

LVM_GETTEXTCOLOR

wParam = 0;                       \\ not used
lParam = 0;                       \\ not used

Description: The LVM_GETTEXTCOLOR message gets the color of the text in a list view window.

Parameters: wParam and lParam are not used.

Return value: The text color (COLORREF).

Macro: (COLORREF)ListView_GetTextColor(hwndLV);

LVM_GETTOPINDEX

wParam = 0;                       \\ not used
lParam = 0;                       \\ not used

Description: The LVM_GETTOPINDEX message gets the index of the first visible item in the list view.

Parameters: wParam and lParam are not used.

Return value: The index of the first visible item (int i).

Macro: (int)ListView_GetTopIndex(hwndLV, ppt);

LVM_GETVIEWRECT

wParam = 0;                       \\ not used
lParam = RECT FAR *prc;           \\ bounding rectangle

Description: The LVM_GETITEMSTATE message gets the bounding rectangle of all of the items in a list view in icon view.

Parameters: wParam is not used. lParam (RECT FAR * prc) is the bounding rectangle. All coordinates are in list view client window units.

Return value: TRUE if successful; FALSE otherwise.

Macro: (BOOL)ListView_GetViewRect(hwndLV, prc);

LVM_HITTEST

wParam = 0;                            \\ not used
lParam = (LV_HITTESTINFO FAR *)pinfo;  \\ position to hit test

Description: The LVM_HITTEST message determines which list view item is at a specified position.

Parameters: wParam is not used. lParam (LV_HITTESTINFO FAR * pinfo) specifies the structure containing the position to hit test.

Return value: The index of the item at the specified position; –1 otherwise.

Macro: (int)ListView_HitTest(hwndLV, pinfo);

LVM_INSERTCOLUMN

wParam = iCol;                    \\ index of the new column
lParam = 0;                       \\ not used

Description: The LVM_INSERTCOLUMN message inserts a new column in a list view window.

Parameters: wParam (int iCol) is the index of the new column. lParam (const LV_COLUMN FAR * pcol) specifies the structure containing column information.

Return value: The index of the new column; –1 if an error occurred.

Macro: (int)ListView_InsertColumn(hwndLV, iCol, pcol);

LVM_INSERTITEM

wParam = 0;                           \\ not used
lParam = (const LV_ITEM FAR *)pitem;  \\ new item information

Description: The LVM_INSERTITEM message inserts a new item in a list view window.

Parameters: wParam is not used. lParam (const LV_ITEM FAR * pitem) specifies the structure containing item information. The iItem member specifies the index of the new item. The iSubItem member must be zero; this message cannot be used to insert subitems.

Return value: The index of the new item if successful; –1 otherwise.

Macro: (int)ListView_InsertItem(hwndLV, pitem);

LVM_REDRAWITEMS

wParam = 0;                       \\ not used
lParam = MAKELONG(iFirst, iLast); \\ range of items to redraw

Description: The LVM_REDRAWITEMS message forces a redraw of a range of list view items. The specified items are not actually repainted until the list view window receives a WM_PAINT message. To repaint immediately, call the UpdateWindow function after using this message.

Parameters: wParam is not used. In lParam (MAKELONG iFirst iLast) the high-order word is int iFirst—the index of the first item in the range to redraw. The low-order word is int iLast—the index of the last item in the range to redraw.

Return value: TRUE if successful; FALSE otherwise.

Macro: (BOOL)ListView_RedrawItems(hwndLV, iFirst, iLast);

LVM_SCROLL

wParam = 0;                       \\ not used
lParam = MAKELONG(dx, dy);        \\ horizontal and vertical scrolling

Description: The LVM_SCROLL message scrolls the contents of a list view window. If the current view is report view, the dx parameter must be zero and the dy parameter is the number of lines to scroll.

Parameters: wParam is not used. In lParam (MAKELONG dx dy), the high-order word is int dx—the amount of horizontal scrolling, in pixels. The low-order word is int dy—the amount of vertical scrolling, in pixels.

Return value: TRUE if successful; FALSE otherwise.

Macro: (BOOL)ListView_Scroll(hwndLV, dx, dy);

LVM_SETBKCOLOR

wParam = 0;                       \\ not used
lParam = (COLORREF)clrBk;         \\ background color to set

Description: The LVM_SETBKCOLOR message sets the background color of the list view window.

Parameters: wParam is not used. lParam (COLORREF clrBk) is the background color to set, or CLR_NONE for no background color. List views with background colors redraw themselves significantly faster than those without background colors.

Return value: TRUE if successful; FALSE otherwise.

Macro: (BOOL)ListView_SetBkColor(hwndLV, clrBk);

LVM_SETCALLBACKMASK

wParam = UINT mask;               \\ callback mask
lParam = 0;                       \\ not used

Description: The LVM_SETCALLBACKMASK message sets the callback mask for a list view window.

Parameters: wParam (UINT mask) is the new value of the callback mask. See Table 4, List View Item States, previously in this article for available masks. lParam is not used.

Return value: TRUE if successful; FALSE otherwise.

Macro: (BOOL)ListView_SetCallbackMask(lwndLV, mask);

LVM_SETCOLUMN

wParam = iCol;                    \\ index of the column
lParam = (LV_COLUMN FAR *)pcol;   \\ structure containing column attributes

Description: The LVM_SETCOLUMN message sets the attributes of a list view column.

Parameters: wParam (int iCol) is the index of the column. lParam (LV_COLUMN FAR *pcol) is the structure containing the new attributes. The mask member of the structure specifies which column attributes to set. If the mask member specifies the LVCF_TEXT flag, the pszText member is the address of a null-terminated string, and the cchTextMax is ignored.

Return value: TRUE if successful; FALSE otherwise.

Macro: (BOOL)ListView_SetColumn(hwndLV, iCol, pcol);

LVM_SETCOLUMNWIDTH

wParam = iCol;                    \\ index of the column
lParam = cx;                      \\ new width

Description: The LVM_SETCOLUMNWIDTH message sets the width of a column in report view or list view.

Parameters: wParam (int iCol) is the index of the column. lParam (int cx) is the new width of the column.

Return value: TRUE if successful; FALSE otherwise.

Macro: (BOOL)ListView_SetColumnWidth(hwndLV, iCol, cx);

LVM_SETIMAGELIST

wParam = iImageList;               \\ LVSIL_SMALL, LVSIL_NORMAL, or LVSIL_STATE
lParam = (HIMAGELIST) himl;        \\ handle of the image list

Description: The LVM_SETIMAGELIST message sets the image list used for drawing list view items.

Parameters: wParam (int ImageList) is LVSIL_SMALL for a small icons, LVSIL_NORMAL for standard icons, or LVSIL_STATE for a state image list. lParam (HIMAGELIST himl) is the handle to the image list.

Return value: TRUE if successful; FALSE otherwise.

Macro: (BOOL)ListView_SetImageList(hwndLV, himl, iImageList);

LVM_SETITEM

wParam = 0;                           \\ not used
lParam = (const LV_ITEM FAR *)pitem;  \\ new item attributes

Description: The LVM_SETITEM message sets a list view item's attributes.

Parameters: wParam is not used. lParam (const LV_ITEM FAR * pitem) specifies the structure that contains the new item attributes.

Return value: TRUE if successful; FALSE otherwise.

Macro: (BOOL)ListView_SetItem(hwndLV, pitem);

LVM_SETITEMCOUNT

wParam = cItems;                  \\ count of the items
lParam = 0;                       \\ not used

Description: The LVM_SETITEMCOUNT message sets the item count of a list view.

Parameters: wParam (int cItems) is the count of the items. lParam is not used.

Return value: TRUE if successful; FALSE otherwise.

Macro: (BOOL)ListView_SetItemCount(hwndLV, cItems);

LVM_SETITEMPOSITION

wParam = i;                       \\ item index
lParam = MAKELONG(x, y);          \\ top-left corner of the new item

Description: The LVM_SETITEMPOSITION message sets the position of a list view item in standard icon or small icon view relative to the list view rectangle.

Parameters: wParam (int i) is the index of the list view item. lParam (int x y) is the top-left corner of the new item in list view client coordinates. The high-order word is x, and the low-order word is y.

Return value: TRUE if successful; FALSE otherwise.

Macro: (BOOL)ListView_SetItemPosition(hwndLV, i x, y);

LVM_SETITEMSTATE

wParam = i;                       \\ index of the item
lParam = (LV_ITEM FAR *)plvi;     \\ new item state

Description: The LVM_SETITEMSTATE message sets the state of a list view item.

Parameters: wParam (int i) is the index of the item. lParam (LV_ITEM FAR * plvi) specifies the two fields that need to be filled in, as follows:

Return value: TRUE if successful; FALSE otherwise. However, the message returns a VOID.

Macro: (VOID)ListView_SetItemState(hwndLV, I, data, mask);

LVM_SETITEMTEXT

wParam = i;                       \\ index of the item
lParam = (LV_ITEM FAR *)plvi;     \\ new item text

Description: The LVM_SETITEMTEXT message sets the text of a list view item or subitem.

Parameters: wParam (int i) is the index of the item. lParam (LV_ITEM FAR * plvi) specifies the fields lvi.iSubItem and lvi.pszText. These fields should be filled in as follows:

Return value: TRUE if successful; FALSE otherwise.

Macro: (BOOL)ListView_SetItemText(hwndLV, I, iSubItem, pszText);

LVM_SETTEXTBKCOLOR

wParam = 0;                       \\ not used
lParam = (COLORREF)clrText;       \\ new background text color

Description: The LVM_SETTEXTBKCOLOR message sets the background text color of a list view window.

Parameters: wParam is not used. lParam (COLORREF clrText) is the new background text color.

Return value: TRUE if successful; FALSE otherwise.

Macro: (BOOL)ListView_SetTextBkColor(hwndLV, clrText);

LVM_SETTEXTCOLOR

wParam = 0;                       \\ not used
lParam = (COLORREF)clrText;       \\ new text color

Description: The LVM_SETTEXTCOLOR message sets the text color in a list view window.

Parameters: wParam is not used. lParam (COLORREF clrText) is the new text color.

Return value: TRUE if successful; FALSE otherwise.

Macro: (BOOL)ListView_SetTextColor(hwndLV, clrText);

LVM_SORTITEMS

wParam = (LPARAM)lParamSort;          \\ application-defined parameter
lParam = (PFNLVCOMPARE) pfnCompare;   \\ sorting callback function

Description: The LVM_SORTITEMS message sorts list view items using an application-defined comparison function. The index of each item changes to reflect the new sequence. The comparison function must return a negative value if the first item should precede the second, a positive value if the first item should follow the second, or zero if the two items are equivalent. The lParam1 and lParam2 parameters correspond to the lParam member of the LV_ITEM structure for the two items being compared. The lParamSort parameter is identical to the value passed to the ListView_SortItems macro.

Parameters: wParam (LPARAM lParamSort) is the application-defined parameter that is passed to the comparison function. lParam (PFNLVCOMPARE pfnCompare) is a callback function that does the comparison. The comparison function has the following form:

int CALLBACK CompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort);

Return value: TRUE if successful; FALSE otherwise.

Macro: (BOOL)ListView_SortItems(hwndLV, pfnCompare, lParamSort);

LVM_UPDATE

wParam = i;                       \\ index of the item
lParam = 0;                       \\ not used

Description: The LVM_UPDATE message updates a list view item. If the list view has the LVS_AUTOARRANGE style, the list view will be arranged.

Parameters: wParam (int i) is the index of the item to update. lParam is not used.

Return value: TRUE if successful; FALSE otherwise.

Macro: (BOOL)ListView_Update(hwndLV, i);

List View Structures

The following structures are used with the macros described in the previous section and with the notifications described in the next section. You will notice that most of these structures use masks heavily to determine the valid members of the structure. You will also notice that some masks can be used with more than one structure.

LV_COLUMN

typedef struct _LV_COLUMN {
    UINT mask;        \\ specifies which members are valid
    int fmt;          \\ format of the column
    int cx;           \\ width of the column in pixels
    LPSTR pszText;    \\ column heading text
    int cchTextMax;   \\ size of text buffer
    int iSubItem;     \\ index of the subitem associated with the column
} LV_COLUMN;

The LV_COLUMN structure contains information about a column in report view. It can also be used to receive information about a column. This structure is used with the ListView_GetColumn, ListView_SetColumn, ListView_InsertColumn, and ListView_DeleteColumn macros. The LV_COLUMN structure includes the following members:

Table 8. List View Column Format Masks

Value Meaning
LVCF_ALL All members of the structure are valid.
LVCT_FMT The .fmt member of the structure is valid.
LVCF_WIDTH The .cx member of the structure is valid.
LVCF_TEXT The .pszText member of the structure is valid.
LVCF_SUBITEM The .iSubItem member of the structure is valid.

LV_DISPINFO

typedef struct _LV_DISPINFO {
    NMHDR hdr;        \\ common control notification structure
    LV_ITEM item;     \\ list view item
} LV_DISPINFO;

The LV_DISPINFO structure is used with the LVN_GETDISPINFO and LVN_SETDISPINFO notifications to get and set information about a list view item. These notifications are sent only if the parent window is responsible for maintaining certain information. The LV_DISPINFO structure includes the following members:

LV_DRAGITEMINFO

typedef struct _LV_DRAGITEMINFO {
    HWND hwndRoot;    \\ handle of the drag root window
    HWND hwndFrom;    \\ handle of the drag source window
    UINT fmt;         \\ format of the drag data
    LPARAM lParam;    \\ application-defined data
    POINT ptOffset;   \\ screen coordinates of where drag began
} LV_DRAGITEMINFO;

The LV_DRAGITEMINFO structure contains information about the item being dragged. This structure is used with the ListView_DragItem macro. The LV_DRAGITEMINFO structure includes the following members:

LV_FINDINFO

typedef struct _LV_FINDINFO {
    UINT flags;     \\ type of search to perform
    LPCSTR psz;     \\ string to compare with
    LPARAM lParam;  \\ value to compare with LV_ITEM's lParam member
} LV_FINDINFO;

The LV_FINDINFO structure contains information used to search for a list view item. This structure is used with the ListView_FindItem macro. The LV_FINDINFO structure includes the following members:

Table 9. List View Find Flags

Flag Meaning
LVFI_PARAM Searches based on the lParam member. The lParam member of the matching item's LV_ITEM structure must match the lParam member of this structure. If this flag is specified, all other flags are ignored.
LVFI_STRING Searches based on item text. Unless additional flags are specified, the item text of the matching item must exactly match the string that the psz member points to.
LVFI_SUBSTRING Matches if the string the psz member points to is contained anywhere in the item text. This flag cannot be used with LVFI_PARTIAL. This flag implies LVFI_STRING.
LVFI _PARTIAL Matches if the item text begins with the string that the psz member points to. This flag implies LVFI_STRING.
LVFI_NOCASE Ignores case in string comparisons. This flag is ignored if LVFI_STRING is not specified.

LV_HITTESTINFO

typedef struct _LV_HITTESTINFO {
    POINT pt;      \\ position to hit test
    UINT flags;    \\ receives results of hit test
} LV_HITTESTINFO;

The LV_HITTESTINFO structure contains information about a hit test. This structure is used with the ListView_HitTest macro. The structure includes the following members:

Table 10. List View Hit Test Flags

Flag Meaning
LVHT_NOWHERE The position is inside the list view's client window but not over a list item.
LVHT_ONITEMICON The position is over a list item's icon.
LVHT_ONITEMLABEL The position is over a list item's text.
LVHT_ONITEM The position is on an item. This is a combination of LVHT_ONEITEMICON and LVHT_ONITEMLABEL.
LVHT_ABOVE The position is above the list view's client area.
LVHT_BELOW The position is below the list view's client area.
LVHT_TORIGHT The position is to the right of the list view's client area.
LVHT_TOLEFT The position is to the left of the list view's client area.

LV_ITEM

typedef struct _LV_ITEM {
    UINT mask;        \\ mask specifying which members are valid
    int iItem;        \\ index of the item
    int iSubItem;     \\ index of the subitem
    UINT state;       \\ item state
    UINT stateMask;   \\ state of item
    LPSTR pszText;    \\ item text
    int cchText;      \\ size of text buffer
    int iImage;       \\ index of the icon image in the image list
    LPARAM lParam;    \\ application-defined item data
} LV_ITEM;

The LV_ITEM structure contains the attributes of a list view item. This structure is used by a number of macros (all of which send messages), including ListView_GetItem, ListView_SetItem, ListView_InsertItem, and ListView_DeleteItem. The LV_ITEM structure includes the following members:

Table 11. List View Item Masks

Value Meaning
LVIF_TEXT The pszText member is valid.
LVIF_IMAGE The iImage member is valid.
LVIF_PARAM The lParam member is valid.
LVIF_STATE The state member is valid.

LV_KEYDOWN

typedef struct _LV_KEYDOWN {
    NMHDR hdr;     \\ common control notification structure
    WORD wVKey;    \\ virtual key code
    UINT flags;    \\ always zero
} LV_KEYDOWN;

The LV_KEYDOWN structure contains information about a keyboard event in a list view window. This structure is used with the LVN_KEYDOWN notification. The structure includes the following members:

NM_LISTVIEW

typedef struct _NM_LISTVIEW {
    NMHDR hdr;       \\ common control notification structure
    int iItem;       \\ the list view item
    int iSubItem;    \\ the subitem
    UINT uNewState;  \\ new item state
    UINT uOldState;  \\ old item state
    UINT uChanged;   \\ which item attribute changed
    POINT ptAction;  \\ location where the event occurred
} NM_LISTVIEW;

The NM_LISTVIEW structure contains information about a list view notification. The address of this structure is specified as the lParam parameter of the WM_NOTIFY message for several list view notifications. The structure includes the following members:

List View Notification Messages

Oh dear, yet another list. I promise that this is the last one (in this article). Feel free to skip this section if you are sick of reading lists. The following table lists the notification messages that Windows sends to list view windows. All of these notifications are sent via a WM_NOTIFY message to the list view window's parent window.

Table 12. List View Notification Messages

Message Description
LVN_BEGINDRAG Sent when the user begins a drag-and-drop operation involving the left mouse button.
LVN_BEGINLABELEDIT Sent when the user begins to edit the label of an item.
LVN_BEGINRDRAG Sent when the user begins a drag-and-drop operation involving the right mouse button.
LVN_COLUMNCLICK Sent when the user clicks a column.
LVN_DELETEALLITEMS Sent when all items in the list view are deleted.
LVN_DELETEITEM Sent when an item is deleted.
LVN_ENDDRAG Sent when default processing for a drag-and-drop operation involving the left mouse button has ended.
LVN_ENDLABELEDIT Sent when the user finishes editing the label of an item.
LVN_ENDRDRAG Sent when default processing for a drag-and-drop operation involving the right mouse button has ended.
LVN_GETDISPINFO Requests that a list view's parent window provide information for displaying or sorting an item.
LVN_INSERTITEM Sent when a new item is inserted.
LVN_ITEMCHANGED Sent when an item has changed.
LVN_ITEMCHANGING Sent when an item is changing. Returning FALSE for this notification will disallow the change.
LVN_KEYDOWN Sent when a key has been pressed.
LVN_SETDISPINFO Sent when the parent window must update the information it maintains for an item.

Summary

Now you know how to create and use the new list view and column header windows that are built into Windows 95. These two new windows will really help you give your application the same look as the Windows 95 shell. So, find some areas in your application that would benefit from this new look, and use the code that I have given you to add this functionality to your application. Be the first one on your block to adopt the visual appeal of the new shell, and sneer at those who stick to the old method of displaying information.

I am really excited about my next article, which covers image lists and the new tree view window. Finally, we are giving you the ability to create a hierarchical tree that is built into the system. It's about time. The article is called "Win32 Common Controls, Part 5: Image Lists and Tree View Windows."