windowswinapicomboboxbackgroundbrush

How do I use WM_CTLCOLORLISTBOX?


I'm trying to set the brush to be used in the combobox's background color, like this:

    case WM_CTLCOLORLISTBOX:
      if(hwndCombo == (HWND)lParam)
      {
        return (LRESULT) hBrush;
      }
      else
      {
        break;
      }

However, hwndCombo == (HWND)lParam is never true. I can see the message is sent because this works:

case WM_CTLCOLORLISTBOX:
        return (LRESULT) hBrush;

but I'd like to select those I'm going to set the color. What am I missing?

full code:

#pragma comment(lib, "user32.lib")
#pragma comment(lib, "Comctl32.lib")
#pragma comment(lib, "Gdi32.lib")
#pragma comment(lib, "Comdlg32.lib")

#define WIN32_LEAN_AND_MEAN
#define UNICODE
#define _UNICODE

#include <windows.h>
#include <winuser.h>
#include <assert.h>

#define COUNTOF(a) (sizeof(a)/sizeof(a[0]))

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
HFONT getDefaultFont();
void SetDefaultFont(HWND hwnd);

HFONT hDefaultSystemFont;

HINSTANCE g_hinst;

const wchar_t *items[] =
{ 
  L"Windows", L"Mac", 
  L"FreeBSD", L"Arch",
};
HWND hwndCombo;
HBRUSH hBrush;

enum
{
  ID_COMBO = 10,
  ID_BTN1,
};

int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
                    PWSTR lpCmdLine, int nCmdShow) {

    HWND hwnd;
    MSG  msg ;    
    WNDCLASSW wc = {0};
    wc.lpszClassName = L"Application";
    wc.hInstance     = hInstance ;
    wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
    wc.lpfnWndProc   = WndProc ;
    wc.hCursor       = LoadCursor(0,IDC_ARROW);

    g_hinst = hInstance;
  
    RegisterClassW(&wc);
    hwnd = CreateWindowW(wc.lpszClassName, L"",
                  WS_OVERLAPPEDWINDOW | WS_VISIBLE,
                  100, 100, 300, 170, 0, 0, hInstance, 0);  


    while (GetMessage(&msg, NULL, 0, 0))
    {
        DispatchMessage(&msg);
    }

    return (int) msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, 
        WPARAM wParam, LPARAM lParam) {

    switch(msg)
    {
    
        case WM_CREATE:
        {
              hwndCombo = CreateWindow(L"Combobox", NULL, 
                    WS_CHILD | WS_VISIBLE | CBS_DROPDOWN,
                    10, 10, 120, 110, hwnd, (HMENU) ID_COMBO, g_hinst, NULL);
              for (int i = 0; i < COUNTOF(items); i++ )
              {
                SendMessageW(hwndCombo, CB_ADDSTRING, 0, (LPARAM) items[i]);
              }
              SetDefaultFont(hwndCombo);

              HWND btn1 =
              CreateWindow(L"Button", L"Click me", 
                    WS_CHILD | WS_VISIBLE,
                    5, 40, 90, 25, hwnd, (HMENU) ID_BTN1, g_hinst, NULL); 
              SetDefaultFont(btn1);
              hBrush = CreateSolidBrush(RGB(0, 128, 0));
        }
        break;

        case WM_DESTROY:
            DeleteObject(hDefaultSystemFont);
            hDefaultSystemFont = NULL;
            PostQuitMessage(0);
            break;

        case WM_CTLCOLORLISTBOX:
          if(hwndCombo == (HWND)lParam)
          {
            return (LRESULT) hBrush;
          }
          else
          {
            break;
          }
    }
  
    return DefWindowProcW(hwnd, msg, wParam, lParam);
}


HFONT getDefaultFont()
{
  if(hDefaultSystemFont == NULL) {
    NONCLIENTMETRICS ncm;
    ncm.cbSize = sizeof(NONCLIENTMETRICS);
    SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &ncm, 0);
    hDefaultSystemFont = CreateFontIndirect(&ncm.lfMessageFont);
  }
  return hDefaultSystemFont;
}


void SetDefaultFont(HWND hwnd)
{
    SendMessage(hwnd, WM_SETFONT, (LPARAM) getDefaultFont(), TRUE);
}

Solution

  • The HWND provided in the lParam of a WM_CTLCOLORLISTBOX message is for a ListBox, not for a ComboBox. You can get the HWND of a ComboBox's ListBox by using GetComboBoxInfo() or CB_GETCOMBOBOXINFO.

    UPDATE: You can alternatively use GetParent() on the HWND provided by WM_CTLCOLORLISTBOX to get its owning ComboBox's HWND.