Search code examples
winapiscrollbarhigh-contrast

How to make standart WS_VSCROLL scrollbar style same as other scrollbars in the system?


I'm using high contrast theme for darkmode in Windows 10. I'm trying to create a window with scrolling functionality on pure low level API, no external libraries.

However, the style of the default scroll bar is vastly different to all the other scrollbars in the system, observe:

enter image description here

It seems like it is disabled, but actually it's working just fine. Just looks different. Take a look at the up/down arrows and lack of white borders.

Here is how it looks on normal theme:

enter image description here

Seems almost identical, other than some slight colour variation (my window's scrollbar have gradient effect applied, while console's window is just plain colour). Both windows have no focus at the moment of screenshot.

My class:

DWORD style_ex = WS_EX_COMPOSITED;
DWORD style = WS_POPUP | WS_THICKFRAME | WS_VSCROLL;

// Register Window Class Atom ==============================================================
WNDCLASSEX wc;
wc.cbSize = sizeof(WNDCLASSEX);                 // Structure size in bytes
wc.style = CS_DBLCLKS;                          // Class style, any combination
wc.lpfnWndProc = dbgWndProc;                    // Window callback function
wc.cbClsExtra = 0;                              // Extra Class Memory (max 40B)
wc.cbWndExtra = 0;                              // Extra Window Memory (max 40B)
wc.hInstance = exec_adress;                     // Handle to module's instance
wc.hIcon = ico;                                 // Def. icon for all windows
wc.hCursor = LoadCursor(NULL, IDC_ARROW);       // Def. cursor for all windows
wc.hbrBackground = backgrnd;                    // Def. brush for WM_ERASEBKGND
wc.lpszMenuName = NULL;                         // Def. menu name for all w.
wc.lpszClassName = L"superSimpleWindow";        // Name of the Class (Atom)
wc.hIconSm = 0;                                 // Def. small icon for all w.
// =========================================================================================

My window:

// Create Window ===========================================================================
main_wnd = CreateWindowEx(
    style_ex,               //   [I] Extended window style
    (LPCWSTR)main_class,    // [I|O] Class Atom / Class Atom String
    NULL,                   // [I|O] Window name String (Title)
    style,                  //   [I] Window style (WS_OVERLAPPED = 0x0)
    x, y, w, h,             //   [I] PosX, PoxY, Width, Height
    NULL,                   // [I|O] Handle to this window's parent
    NULL,                   // [I|O] Handle to menu / Child-window ID
    exec_adress,            // [I|O] Handle to instance of the module
    NULL);                  // [I|O] CREATESTRUCT ptr. for lParam of WM_CREATE
// =========================================================================================

UpdateWindow(main_wnd);
ShowWindow(main_wnd, SW_NORMAL);

What is causing this strange style differences? How can I make my scrollbar look exactly the same as all the other windows' scrollbars?


Solution

  • I already gave up on this issue, but accidentally found the solution for this problem. The key to having correct title bars is to have correct manifest file embedded in your program. The manifest should look like this:

    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
        <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
            <security>
                <requestedPrivileges>
                <requestedExecutionLevel level="asInvoker" uiAccess="false" />
                </requestedPrivileges>
            </security>
        </trustInfo>
        <application xmlns="urn:schemas-microsoft-com:asm.v3">
            <windowsSettings>
                <dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
                <dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2</dpiAwareness>
            </windowsSettings>
        </application>
        <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
            <application>
                <!-- Windows 10 and Windows 11 -->
                <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
                <!-- Windows 8.1 -->
                <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
                <!-- Windows 8 -->
                <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
                <!-- Windows 7 -->
                <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
                <!-- Windows Vista -->
                <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/> 
            </application>
        </compatibility>
    </assembly>
    

    The trustInfo and dpiAware is not mandatory, but it's useful in any modern application.

    The most important thing here is actually the compatibility section of the manifest. Including this makes the scrollbars exactly the same as any other in the system.

    You might also want to include this part, after <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">:

    <dependency>
        <dependentAssembly>
            <assemblyIdentity   type="win32"
                                name="Microsoft.Windows.Common-Controls"
                                version="6.0.0.0"
                                processorArchitecture="*"
                                publicKeyToken="6595b64144ccf1df"
                                language="*"/>
        </dependentAssembly>
    </dependency>
    

    This will make your standard controls (like buttons, radio buttons, edit fields, etc) look much nicer and modern, but it's not actually needed for correct scrollbars.