Unable to set my CStatusBar background colour

ChuckieAJ 201 Reputation points
2025-02-03T11:30:25.02+00:00

I am surprised that I can't do this because the File Explorer in Windows 11 has a dark statusbar. So initially I tried:

SetWindowTheme(m_wndStatusBar.GetSafeHWnd(), L"DarkMode_Explorer", nullptr);

And it did nothing. I then tried:

// Set dark mode background color
m_wndStatusBar.GetStatusBarCtrl().SetBkColor(DarkModeTools::darkBkColor);

And it still does not work:

Image

Windows API - Win32
Windows API - Win32
A core set of Windows application programming interfaces (APIs) for desktop and server applications. Previously known as Win32 API.
2,736 questions
C++
C++
A high-level, general-purpose programming language, created as an extension of the C programming language, that has object-oriented, generic, and functional features in addition to facilities for low-level memory manipulation.
3,857 questions
{count} votes

Accepted answer
  1. Castorix31 86,986 Reputation points
    2025-02-04T14:33:18.5133333+00:00

    You can draw the background in WM_ERASEBKGND and draw the text with Owner-drawn

    A test in C++/Win32 :

    User's image

    #include <windows.h>
    #include <tchar.h>
    
    #include <commctrl.h>
    #pragma comment (lib, "comctl32")
    
    #include <Vsstyle.h>
    #include <vssym32.h>
    #include <uxtheme.h> 
    #pragma comment(lib, "UxTheme")
    
    #pragma comment(linker,"\"/manifestdependency:type='win32' \
    name='Microsoft.Windows.Common-Controls' version='6.0.0.0' \
    processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
    
    HINSTANCE hInst;
    LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
    int nWidth = 600, nHeight = 400;
    #define IDC_STATUSBAR 10
    #define IDC_BUTTON 11
    
    VOID __inline UpdateStatusBar(HWND hWndStatusBar, LPCWSTR lpszStatusString, WORD partNumber, WORD displayFlags)
    {
    	SendMessage(hWndStatusBar, SB_SETTEXT, partNumber | displayFlags, (LPARAM)lpszStatusString);
    }
    
    LRESULT CALLBACK StatusBarSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, UINT_PTR, DWORD_PTR);
    
    BOOL IsDarkMode();
    BOOL _bDarkMode = FALSE;
    COLORREF GetButtonBackgroundColor();
    COLORREF _colorBackground = RGB(51, 51, 51);
    
    typedef BOOL(WINAPI* fnAllowDarkModeForWindow)(HWND hWnd, BOOL allow);
    fnAllowDarkModeForWindow pAllowDarkModeForWindow;
    
    enum PreferredAppMode { Default, AllowDark, ForceDark, ForceLight, Max };
    typedef PreferredAppMode(WINAPI* fnSetPreferredAppMode)(PreferredAppMode appMode);
    fnSetPreferredAppMode pSetPreferredAppMode;
    
    int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow)
    {
    	hInst = hInstance;
    	WNDCLASSEX wcex =
    	{
    		sizeof(WNDCLASSEX), CS_HREDRAW | CS_VREDRAW, WndProc, 0, 0, hInst, LoadIcon(NULL, IDI_APPLICATION),
    		LoadCursor(NULL, IDC_ARROW), (HBRUSH)(COLOR_WINDOW + 1), NULL, TEXT("WindowClass"), NULL,
    	};
    	if (!RegisterClassEx(&wcex))
    		return MessageBox(NULL, TEXT("Cannot register class !"), TEXT("Error"), MB_ICONERROR | MB_OK);
    	int nX = (GetSystemMetrics(SM_CXSCREEN) - nWidth) / 2, nY = (GetSystemMetrics(SM_CYSCREEN) - nHeight) / 2;
    	HWND hWnd = CreateWindowEx(0, wcex.lpszClassName, TEXT("Test"), WS_OVERLAPPEDWINDOW, nX, nY, nWidth, nHeight, NULL, NULL, hInst, NULL);
    	if (!hWnd)
    		return MessageBox(NULL, TEXT("Cannot create window !"), TEXT("Error"), MB_ICONERROR | MB_OK);
    	ShowWindow(hWnd, SW_SHOWNORMAL);
    	UpdateWindow(hWnd);
    	MSG msg;
    	while (GetMessage(&msg, NULL, 0, 0))
    	{
    		TranslateMessage(&msg);
    		DispatchMessage(&msg);
    	}	
    	return (int)msg.wParam;
    }
    
    LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
    	static HWND hWndButton = NULL;
    	static HWND hWndStatusBar = NULL;
    	int wmId, wmEvent;
    	switch (message)
    	{
    	case WM_CREATE:
    	{
    		hWndButton = CreateWindowEx(0, L"Button", L"Click", WS_CHILD | WS_VISIBLE | BS_PUSHLIKE, 100, 60, 60, 32, hWnd, (HMENU)IDC_BUTTON, hInst, NULL);
    
    		HMODULE hDll = LoadLibrary(L"UXTheme.dll");
    		pSetPreferredAppMode = (fnSetPreferredAppMode)GetProcAddress(hDll, MAKEINTRESOURCEA(135));
    		if (pSetPreferredAppMode)
    			pSetPreferredAppMode(AllowDark);
    		pAllowDarkModeForWindow = (fnAllowDarkModeForWindow)GetProcAddress(hDll, MAKEINTRESOURCEA(133));
    		if (pAllowDarkModeForWindow)
    			pAllowDarkModeForWindow(hWndButton, TRUE);		
    		
    		SetWindowTheme(hWndButton, L"Explorer", NULL);
    
    		_bDarkMode = IsDarkMode();	
    
    		hWndStatusBar = CreateWindow(STATUSCLASSNAME, L"",
    			WS_VISIBLE | WS_CHILD | WS_BORDER | SBS_SIZEGRIP,// | SBARS_TOOLTIPS,
    			0, 0, 0, 0, hWnd, (HMENU)IDC_STATUSBAR, hInst, NULL);
    		RECT rect;
    		GetClientRect(hWnd, &rect);
    		int ptArray[5];
    		ptArray[0] = 0;
    		ptArray[2] = rect.right;
    		ptArray[1] = ptArray[2] - 300;
    		ptArray[0] = 100;
    		SendMessage(hWndStatusBar, SB_SETPARTS, sizeof(ptArray) / sizeof(ptArray[0]), (LPARAM)(LPINT)ptArray);
    		UpdateStatusBar(hWndStatusBar, L"Part 0", 0, SBT_POPOUT | SBT_OWNERDRAW);
    		UpdateStatusBar(hWndStatusBar, L"Part 1", 1, SBT_POPOUT | SBT_OWNERDRAW);
    		UpdateStatusBar(hWndStatusBar, L"Part 2", 2, SBT_POPOUT | SBT_OWNERDRAW);
    		SetWindowSubclass(hWndStatusBar, StatusBarSubclassProc, 0, 0);
    		return 0;
    	}
    	break;
    	case WM_DRAWITEM:
    	{		
    		DRAWITEMSTRUCT* lpDIS;
    		lpDIS = (LPDRAWITEMSTRUCT)lParam;
    		int savedDC = SaveDC(lpDIS->hDC);
    		if (lpDIS->hwndItem == hWndStatusBar)
    		{
    			RECT rect;
    			COLORREF crOldTextColor, crOldBkColor;
    			int nOldMode;
    			WCHAR sDrawText[255] = L"";
    
    			int nID = lpDIS->itemID;
    			CopyRect(&rect, &lpDIS->rcItem);
    			if (lpDIS->itemData)
    				lstrcpy(sDrawText, (LPWSTR)lpDIS->itemData);
    
    			nOldMode = SetBkMode(lpDIS->hDC, TRANSPARENT);
    			if (nID == 0 || nID == 1 || nID == 2)
    			{
    				if (nID == 0)
    					crOldTextColor = SetTextColor(lpDIS->hDC, RGB(0, 0, 255));
    				else if(nID == 1)
    					crOldTextColor = SetTextColor(lpDIS->hDC, RGB(0, 255, 0));
    				else
    					crOldTextColor = SetTextColor(lpDIS->hDC, RGB(255, 0, 0));
    				//crOldBkColor = SetBkColor(lpDIS->hDC, GetSysColor(COLOR_BTNFACE));
    				
    				DrawText(lpDIS->hDC, sDrawText, -1, &rect, DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX);								
    
    				SetTextColor(lpDIS->hDC, crOldTextColor);
    				//SetBkColor(lpDIS->hDC, crOldBkColor);				
    				SetBkMode(lpDIS->hDC, nOldMode);
    			}
    		}
    		RestoreDC(lpDIS->hDC, savedDC);
    		return 1;
    	}
    	case WM_SETTINGCHANGE:
    	{
    		WCHAR* plParam = (LPWSTR)lParam;
    		if (plParam)
    		{
    			if (lstrcmp(plParam, TEXT("ImmersiveColorSet")) == 0)
    			{
    				_bDarkMode = IsDarkMode();
    				RedrawWindow(hWndStatusBar, NULL, NULL, RDW_UPDATENOW | RDW_INVALIDATE | RDW_ERASE);
    				SendMessageW(hWndButton, WM_THEMECHANGED, 0, 0);
    			}
    		}
    		return 0;
    	}
    	break;
    	case WM_SIZE:
    	{
    		SendMessage(hWndStatusBar, message, wParam, lParam);
    		return 0;
    	}
    	case WM_COMMAND:
    	{
    		wmId = LOWORD(wParam);
    		wmEvent = HIWORD(wParam);
    		switch (wmId)
    		{
    		case IDC_BUTTON:
    		{
    			if (wmEvent == BN_CLICKED)
    			{
    				Beep(1000, 10);
    			}
    		}
    		break;
    		default:
    			return DefWindowProc(hWnd, message, wParam, lParam);
    		}
    	}
    	break;
    	case WM_PAINT:
    	{
    		PAINTSTRUCT ps;
    		HDC hDC = BeginPaint(hWnd, &ps);
    
    		EndPaint(hWnd, &ps);
    	}
    	break;
    	case WM_DESTROY:
    	{
    		PostQuitMessage(0);
    		return 0;
    	}
    	break;
    	default:
    		return DefWindowProc(hWnd, message, wParam, lParam);
    	}
    	return 0;
    }
    
    LRESULT CALLBACK StatusBarSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, UINT_PTR, DWORD_PTR)
    {
    	switch (msg)
    	{
    	case WM_ERASEBKGND:
    	{
    		RECT rect;
    		GetClientRect(hwnd, &rect);
    		COLORREF color = GetButtonBackgroundColor();
    		HBRUSH hBrush = CreateSolidBrush(color);
    		FillRect((HDC)wParam, &rect, hBrush);
    		DeleteObject(hBrush);
    		return 0;
    	}
    	break;
    	}
    	return DefSubclassProc(hwnd, msg, wParam, lParam);
    }
    
    BOOL IsDarkMode()
    {
    	DWORD nValue = 0;
    	DWORD nSize = sizeof(nValue);
    	HKEY hKey;
    	if (RegOpenKeyEx(HKEY_CURRENT_USER,
    		L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize",
    		0, KEY_READ, &hKey) == ERROR_SUCCESS)
    	{
    		RegQueryValueEx(hKey, L"AppsUseLightTheme", nullptr, nullptr, (LPBYTE)&nValue, &nSize);
    		RegCloseKey(hKey);
    	}
    	return nValue == 0; // 0 = Dark mode, 1 = Light mode
    }
    
    COLORREF GetButtonBackgroundColor()
    {
    	if (IsDarkMode())
    		return _colorBackground;
    	return GetSysColor(COLOR_BTNFACE);
    }
    
    
    
    1 person found this answer helpful.

3 additional answers

Sort by: Most helpful
  1. Deleted

    This answer has been deleted due to a violation of our Code of Conduct. The answer was manually reported or identified through automated detection before action was taken. Please refer to our Code of Conduct for more information.


    Comments have been turned off. Learn more

  2. Deleted

    This answer has been deleted due to a violation of our Code of Conduct. The answer was manually reported or identified through automated detection before action was taken. Please refer to our Code of Conduct for more information.


    Comments have been turned off. Learn more

  3. Minxin Yu 12,676 Reputation points Microsoft Vendor
    2025-02-04T03:22:53.9733333+00:00

    Hi,

    Set theme CMFCVisualManagerOffice2007 Office2007_ObsidianBlack is an option.

    Use MFC class and C(MDI)FrameWndEx class.

    CMFCToolBar m_wndToolBar;

    CMFCStatusBar m_wndStatusBar;

    DockPane(&m_wndToolBar);

    User's image

    Best regards,

    Minxin Yu


    If the answer is the right solution, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment".

    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.


Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.