Aldaviva / DarkNet

🌓 Enable native Windows dark mode for your WPF and Windows Forms title bars.
https://www.nuget.org/packages/DarkNet/
Apache License 2.0
66 stars 2 forks source link

Dark scrollbars #6

Open AndnixSH opened 1 year ago

AndnixSH commented 1 year ago

Do you know if it's possible to enable dark scrollbars natively in WinForm? Notepad++ and Windows Explorer are using native dark scrollbars

Aldaviva commented 1 year ago

That's a good question. I remember seeing some light scrollbars in WPF but haven't looked at Windows Forms yet. I'll check to see if the Win32 demo has dark scrollbars.

Aldaviva commented 1 year ago

I'm not exactly sure what C++ nonsense this is, but it looks like win32-darkmode is making their native scrollbars dark by wrapping a method from comctl32.dll in FixDarkScrollBar() to force the class name to a different value that gets skinned dark by Windows:

void FixDarkScrollBar()
{
    HMODULE hComctl = LoadLibraryExW(L"comctl32.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32);
    if (hComctl)
    {
        auto addr = FindDelayLoadThunkInModule(hComctl, "uxtheme.dll", 49); // OpenNcThemeData
        if (addr)
        {
            DWORD oldProtect;
            if (VirtualProtect(addr, sizeof(IMAGE_THUNK_DATA), PAGE_READWRITE, &oldProtect))
            {
                auto MyOpenThemeData = [](HWND hWnd, LPCWSTR classList) -> HTHEME {
                    if (wcscmp(classList, L"ScrollBar") == 0)
                    {
                        hWnd = nullptr;
                        classList = L"Explorer::ScrollBar";
                    }
                    return _OpenNcThemeData(hWnd, classList);
                };

                addr->u1.Function = reinterpret_cast<ULONG_PTR>(static_cast<fnOpenNcThemeData>(MyOpenThemeData));
                VirtualProtect(addr, sizeof(IMAGE_THUNK_DATA), oldProtect, &oldProtect);
            }
        }
    }
}

win32-darkmode

I have no idea how to do this in C#, but I might try to give it a shot.

memoarfaa commented 1 year ago

@AndnixSH @Aldaviva To enable dark scrollbars natively in WinForm you need to use "SetWindowTheme" function https://learn.microsoft.com/en-us/windows/win32/api/uxtheme/nf-uxtheme-setwindowtheme

[DllImport("uxtheme.dll", SetLastError = true, ExactSpelling = true, CharSet = CharSet.Unicode)] public static extern int SetWindowTheme(IntPtr hWnd, string pszSubAppName, string pszSubIdList);

SetWindowTheme(control.Handle, "DarkMode_Explorer", "ScrollBar");

example to dark scrollbar and treeView

https://www.mediafire.com/file/4m0uieavnkityje/DarkWinForm.zip/file

2023-08-18_01-04-06

Aldaviva commented 1 year ago

Oh wow thanks, that's way easier than the win32-darkmode C++ function wrapping technique.

I'll try to see if there's a good way to handle this automatically in this library, but at the very least, this method can be called manually (either directly by the dependent UI app, or proxied by this library for convenience).

memoarfaa commented 1 year ago

@Aldaviva Can you support Dark built in ScrollBar of MdiClient and Dark TreeView

Controls.Cast<Control>().ToList().ForEach(control =>
            {
                if (control.GetType().Name == nameof(MdiClient))
                {
                    SetWindowTheme(control.Handle, "DarkMode_Explorer", "ScrollBar");
                }
                else if(control.GetType().Name == nameof(TreeView))
                {
                   control.ForeColor = Color.White;
                   control..BackColor = Color.FromArgb(25, 25, 25);
                    SetWindowTheme(control.Handle, "DarkMode_Explorer", "TreeView");
                }

            });

https://github.com/Aldaviva/DarkNet/assets/12494184/3c0be936-58ff-476c-bd84-73a93a9b9c37

Aldaviva commented 1 year ago

Thanks, let me try that out! I'm definitely not a Forms expert so I appreciate the assistance.

AndnixSH commented 1 year ago

@memoarfaa that's nice. Would it support buttons, textboxes and dropdowns too, like how Notepad++ and foobar2000 implemented them?

image

memoarfaa commented 1 year ago

@Aldaviva @AndnixSH

[DllImport("user32.dll", CharSet = CharSet.Auto)]
 public static extern IntPtr SendMessage(IntPtr hWnd, int msg, int wParam, int lParam);

  Controls.Cast<Control>().ToList().ForEach(control =>
            {
                if (control.GetType().Name == nameof(MdiClient) | control.GetType().BaseType.Name == nameof(ScrollBar))
                {
                    SetWindowTheme(control.Handle, "DarkMode_Explorer", "ScrollBar");
                    // Fix scrollbar corners and TreeView borders not repainting with the new theme
                    SendMessage(control.Handle, WM_THEMECHANGED, 0, 0);
                }
                else if(control.GetType().Name == nameof(TreeView))
                {
                    control.ForeColor = Color.White;
                    control.BackColor = Color.FromArgb(25, 25, 25);
                    SetWindowTheme(control.Handle, "DarkMode_Explorer", "TreeView");
                    SendMessage(control.Handle, WM_THEMECHANGED, 0, 0);
                }
                else if (control.GetType().Name == nameof(Button))
                {

                    ((Button)control).FlatStyle = FlatStyle.System;
                    SetWindowTheme(control.Handle, "DarkMode_Explorer", "Button");
                    SendMessage(control.Handle, WM_THEMECHANGED, 0, 0);
                }

                else if (control.GetType().Name == nameof(TextBox))
                {
                    control.ForeColor = Color.White;
                    SetWindowTheme(control.Handle, "DarkMode_InActiveAddressComposited", "Edit");
                    // Another Dark Theme for Edit
                   // SetWindowTheme(control.Handle, "DarkMode_CFD", "Edit");
                    SendMessage(control.Handle, WM_THEMECHANGED, 0, 0);
                }

                else if (control.GetType().Name == nameof(CheckBox))
                {
                    ((CheckBox)control).FlatStyle = FlatStyle.System;
                    SetWindowTheme(control.Handle, "DarkMode_Explorer", "CheckBox");
                    SendMessage(control.Handle, WM_THEMECHANGED, 0, 0);
                }

                else if (control.GetType().Name == nameof(ComboBox))
                {
                    control.ForeColor = Color.White;
                    control.BackColor = Color.FromArgb(19,19,19);
                    SetWindowTheme(control.Handle, "DarkMode_CFD", "ComboBox");
                    // Another Dark Theme for ComboBox
                    // SetWindowTheme(control.Handle, "DarkMode_AddressComposited", "ComboBox");
                    SendMessage(control.Handle, WM_THEMECHANGED, 0, 0);
                }

            });

2023-08-25_06-49-48

Aldaviva commented 1 year ago

Nice, I'll take a look at that.