Search code examples
c#winformswindows-10

WinForms Dark title bar on Windows 10


I have a WinForms application which automatically adjusts to the dark/light theme on Windows 10. My problem is that the title bar of my window always stays white, regardless which theme the user selects.

enter image description here
Top is current, bottom is how I want it (simulated with Photoshop)

See explorer for example. That is not an UWP app, however it uses a dark title bar on Windows 1903 and newer (when a dark theme is selected).

How can I achieve the same thing? I do not want to use any custom titlebar as I want the application to look and behave like any native application on older Windows versions as well.


Solution

  • So after some long searching, I have finally found the answer for this. The trick is to use dwmapi.dll's DwmSetWindowAttribute and passing the undocumented constant DWMWA_USE_IMMERSIVE_DARK_MODE into the function. In C#, the code for this looks a little something like this (works with both WinForms and WPF):

    /*
    using System.Runtime.InteropServices;
    */
    
    [DllImport("dwmapi.dll")]
    private static extern int DwmSetWindowAttribute(IntPtr hwnd, int attr, ref int attrValue, int attrSize);
    
    private const int DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1 = 19;
    private const int DWMWA_USE_IMMERSIVE_DARK_MODE = 20;
    
    private static bool UseImmersiveDarkMode(IntPtr handle, bool enabled)
    {
        if (IsWindows10OrGreater(17763))
        {
            var attribute = DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1;
            if (IsWindows10OrGreater(18985))
            {
                attribute = DWMWA_USE_IMMERSIVE_DARK_MODE;
            }
    
            int useImmersiveDarkMode = enabled ? 1 : 0;
            return DwmSetWindowAttribute(handle, (int)attribute, ref useImmersiveDarkMode, sizeof(int)) == 0;
        }
    
        return false;
    }
    
    private static bool IsWindows10OrGreater(int build = -1)
    {
        return Environment.OSVersion.Version.Major >= 10 && Environment.OSVersion.Version.Build >= build;
    }