Draw the background of static control with gradient fill when theme is enabled

Recently a customer raised a service incident with Microsoft who reported an issue with their addin unable to visually display property pages in the way that outlook does.

When static controls are created as child of tab controls, they won't inherit backgrounds in XP visual styles. This blog article talks about how to make static control draw its background with gradient fill similar to tab control.

Windows XP (please note, this OS is no longer supported) when running in theme mode, common and user controls appearence changes with Visual styles. They get a new look and feel. Under these conditions when tab controls is created child of dialog it gets the gradient effect. When a static control is made child of this tab control it will not draw its background with same gradient effect. What happens is it draws it background with a regular windows look.

To workaround this problem we need to draw the background of the static control with a gradient look as a tab control. Static controls sends WM_CTLCOLORSTATIC message to its parent (tab control) when it is about to be drawn. By responding to this message, the parent window can use the specified device context handle to set the background colors of the static control.

Steps to workaround the problem:

1) Subclass the Tab control:
   //oldTabProc is the address of original window procedure of the tab control
       oldTabProc = (WNDPROC)GetWindowLong(hWndTab, GWL_WNDPROC);
   //SampleTabProc is the address of original window procedure of the tab control
       SetWindowLong(hWndTab, GWL_WNDPROC, (LONG)SubclassTabProc);
    
2) Handle WM_CTLCOLORSTATIC message in subclassed SubclassTabProc procedure of tab control. We can also handle WM_CTLCOLORBTN to give button gradient effect:    case WM_CTLCOLORBTN:
    case WM_CTLCOLORSTATIC:
    {
            //hbrTabBackground is handle to brush having gradient fill color
            //fBrushInitialized  is initialized to FALSE
     if ((hbrTabBackground == NULL) && !fBrushInitialized)
               {
                   hbrTabBackground = GetTabBackgroundBrush(hwnd);
                   fBrushInitialized = TRUE;
               }
    //Once brush is created below code is called  
            if (hbrTabBackground)
               {
                   RECT rc;
       
                   SetBkMode((HDC)wParam, TRANSPARENT);
                   GetWindowRect((HWND)lParam, &rc);
                   TabCtrl_AdjustRect(hwnd, FALSE, &rc);
                   SetBrushOrgEx((HDC)wParam, -rc.left, -rc.top, NULL);
       
                   return (LRESULT)hbrTabBackground;
               }
           break;

    

3) Creates a logical brush with gradient fill bitmap to be used to painting the static control background.
HBRUSH GetTabBackgroundBrush(HWND hwnd)
   {
       HBRUSH hbrTabBackground = NULL;
       //Open the theme data for "Tab" class
       HTHEME hTheme = OpenThemeData(hwnd, L"Tab");

       //Create pattern brush from tab control theme body part
       if (hTheme)
       {
           HDC hdc = GetDC(NULL);
           if (hdc)
           {
               HDC hdcMem = CreateCompatibleDC(hdc);
               if (hdcMem)
               {
                   INT iBgType;

                   if (SUCCEEDED(GetThemeEnumValue(hTheme, TABP_BODY, 0, TMT_BGTYPE, &iBgType)))
                   {
                       if (iBgType == BT_IMAGEFILE)
                       {
                           SIZE size;

                           if (SUCCEEDED(GetThemePartSize(hTheme, hdcMem, TABP_BODY, 0, NULL, TS_TRUE, &size)))
                           {
                               HBITMAP hbmpMem = CreateCompatibleBitmap(hdc, size.cx, size.cy);
                               if (hbmpMem)
                               {
                                   RECT rc;

                                   SetRect(&rc, 0, 0, size.cx, size.cy);
                                   SelectObject(hdcMem, hbmpMem);

                                   if (SUCCEEDED(DrawThemeBackground(hTheme, hdcMem, TABP_BODY, 0, &rc, NULL)))
                                   {
                                       hbrTabBackground = CreatePatternBrush(hbmpMem);
                                   }

                                   DeleteObject(hbmpMem);
                               }
                           }
                       }
                       else if (iBgType == BT_BORDERFILL)
                       {
                           COLORREF clr;

                           if (SUCCEEDED(GetThemeColor(hTheme, TABP_BODY, 0, TMT_FILLCOLOR, &clr)))
                           {
                               hbrTabBackground = CreateSolidBrush(clr);
                           }
                       }
                   }
                   DeleteDC(hdcMem);
               }
               ReleaseDC(NULL, hdc);
           }
           CloseThemeData(hTheme);
       }
       else
       {
           hbrTabBackground = (HBRUSH)GetClassLongPtr(hwnd, GCLP_HBRBACKGROUND);
       }

       return hbrTabBackground;
   }