May 302008

Windows provides us with a message called WM_CTRLCOLORDLG which helps us in changing background color of a dialog. If we are handling this message then we need to return brush which is used for drawing background color. This means we can provide custom brushes. Don’t forget that we’ve got maintain such custom brushes since these are used even after the call returns. So be careful when destroying these objects.

A quick way to get a brush is get a system cached one by called GetSysColorBrush. Such brushes are not required to be freed. Use system colors such as COLOR_WINDOW, COLOR_3DFACE etc for creating such brushes.

Here is an e.g. on how to do this…

LRESULT CSomeDlg::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
    switch( message )
       // Note that since we are using a system cache brush it's not required to
       // delete this object, but for custom brushes we've got to free them.
       return (LRESULT)GetSysColorBrush( COLOR_HOTLIGHT );
    return CDialog::WindowProc(message, wParam, lParam);

Note that all other ctlcolor messages are send to the owner window of a control except for WM_CTLCOLORDLG which instead is send to the dialog itself. So WM_CTLCOLOREDIT will be send to the parent window of the edit control.

Now as a homework for you try changing background of an edit control. As a hint just change WM_CTLCOLORDLG to WM_CTLCOLOREDIT. Call SetBkColor using dc handle stored in wParam to change background color. Same way for foreground color. Note that for readonly edit controls we get WM_CTLCOLORSTATIC message.

Another option in MFC is to add a message handler for WM_CTLCOLOR (ON_WM_CTLCOLOR), nCtlCode will the type of ctl code given for e.g. CTLCOLOR_DLG for a dialog, CTLCOLOR_EDIT for an edit control.

Have fun changing background colors but keep in mind needs of users too.

Jan 232008

Having trouble with tab control pages’  gray background while using XP themes? Well to solve this problem we need to do some additional housekeeping(AFAIK)…

Add a message map entry for WM_CTLCOLOR


Override OnCtlColor and add following code…

HBRUSH CTabPage::OnCtlColor( CDC* pDC_i, CWnd* pWnd_i, UINT uCntrlType_i )

   // First do default always
   HBRUSH hBrTemp = CDialog::OnCtlColor( pDC_i, pWnd_i, uCntrlType_i );

   // If we have a static control or a dialog control we should return our brush
   // with the DC having a transparent background
   switch( uCntrlType_i )
      case CTLCOLOR_DLG:
          pDC_i->SetBkMode( TRANSPARENT ); // Transparent mode
          hBrTemp = GetSysColorBrush( IsAppThemed() ? COLOR_WINDOW : COLOR_BTNFACE ); // Our brush

   // Return brush to caller
   return hBrTemp;

Note that we don’t need to delete the created brush since we are using a system cached brush. Also it’s good that you create a custom class(something like CTabPage, make this new class derive from CDialog.) and add this code there and then derive all your tab pages from this class instead of CDialog.