I have set the value of system environment variable wx_msw_dark_mode to 1, which means that wxWidgets should use dark mode only when the system does. My PC is not set to use dark mode.
Surprisingly, when running an MSVC-built application in the release mode, it behaves as if Windows were in the dark mode (or rather wx_msw_dark_mode was set to 2), i.e., the controls are drawn partially dark. I can reproduce it with the three last MSVS versions (tested 64-bit shared wxWidgets builds).
The issue does not manifest in the MSVC Debug build (tried only with MSVS 2022) nor gcc or clang release builds. As I find such bug hard to believe, I have restarted the computer several times but nothing has changed, I do not change light/dark setting in Windows (ever) or the value of wx_msw_dark_mode after restart. The issue goes away when I set wx_msw_dark_mode to 0 (without needing restart), i.e., never use dark mode. Can anyone else reproduce this (the computer I tried this on does not show any problems)?
The following screenshot has the minimal sample built in the release build overlapping the window of the minimal sample built in the debug build.

Notebook sample built in release mode:

The wxWidgets and samples were always built with CMake in an out-of-source folder, like this
cmake -G "Visual Studio 17 2022" -DwxBUILD_SAMPLES=ALL -S ../wxWidgets-PB -B .
cmake --build . --config Release
only the generators were different (-G "Visual Studio 16 2019" and -G "Visual Studio 15 2017" -A x64).
MSVS versions:
2022: 17.4.4
2019: 16.11.23
2017: 15.9.49 (minimal sample built with this has also black frame client area?)
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()
As I am still baffled by this issue, I looked into it (with MSVS 2022). It appears the problem is that the function loaded from uxtheme.dll, ShouldUseDarkMode(), often returns true when it should not, but it happens only in the release mode.
I set a breakpoint at darkmode.cpp line 133 (from where ShouldUseDarkMode() is called in wxMSWImpl::ShouldAppsUseDarkMode()) and ran the minimal sample.
Below are the callstacks from the first six breakpoint hits, where ShouldUseDarkMode() returns false as expected only during the first and fifth hits. The function address was always the same (uxtheme.dll!0x00007ff88f999e10).
Hit 1: returns false
> wxmsw330u_core_vc_x64_custom.dll!wxMSWImpl::ShouldUseDarkMode() Line 133 C++ Symbols loaded.
wxmsw330u_core_vc_x64_custom.dll!wxApp::GetRegisteredClassName(const wchar_t * name=0x00007fffc4648e68, int bgBrushCol=15, int extraStyles=0, int flags=1) Line 671 C++ Symbols loaded.
wxmsw330u_core_vc_x64_custom.dll!wxTopLevelWindowMSW::CreateFrame(const wxString & title, const wxPoint & pos={...}, const wxSize & size) Line 422 C++ Symbols loaded.
wxmsw330u_core_vc_x64_custom.dll!wxTopLevelWindowMSW::Create(wxWindow * parent=0x0000000000000000, int id=-1, const wxString & title={...}, const wxPoint & pos={...}, const wxSize & size, long style=541072960, const wxString & name={...}) Line 499 C++ Symbols loaded.
wxmsw330u_core_vc_x64_custom.dll!wxFrame::Create(wxWindow * parent, int id, const wxString & title, const wxPoint & pos={...}, const wxSize & size={...}, long style=541072960, const wxString & name={...}) Line 123 C++ Symbols loaded.
wxmsw330u_core_vc_x64_custom.dll!wxFrame::wxFrame(wxWindow * parent=0x0000000000000000, int id=-1, const wxString & title={...}, const wxPoint & pos={...}, const wxSize & size={...}, long style=541072960, const wxString & name={...}) Line 33 C++ Symbols loaded.
minimal.exe!MyFrame::MyFrame(const wxString & title={...}) Line 142 C++ Symbols loaded.
Hit 2: now returns true
> wxmsw330u_core_vc_x64_custom.dll!wxMSWImpl::ShouldUseDarkMode() Line 133 C++ Symbols loaded.
wxmsw330u_core_vc_x64_custom.dll!wxWindow::MSWCreate(const wchar_t * wclass=0x000001e01ad34750, const wchar_t * title=0x000001e01ad104d0, const wxPoint & pos, const wxSize & size={...}, unsigned long style=47120384, unsigned long extendedStyle=0) Line 4091 C++ Symbols loaded.
wxmsw330u_core_vc_x64_custom.dll!wxTopLevelWindowMSW::CreateFrame(const wxString & title, const wxPoint & pos={...}, const wxSize & size) Line 423 C++ Symbols loaded.
wxmsw330u_core_vc_x64_custom.dll!wxTopLevelWindowMSW::Create(wxWindow * parent=0x0000000000000000, int id=-1, const wxString & title={...}, const wxPoint & pos={...}, const wxSize & size, long style=541072960, const wxString & name={...}) Line 499 C++ Symbols loaded.
wxmsw330u_core_vc_x64_custom.dll!wxFrame::Create(wxWindow * parent, int id, const wxString & title, const wxPoint & pos={...}, const wxSize & size={...}, long style=541072960, const wxString & name={...}) Line 123 C++ Symbols loaded.
wxmsw330u_core_vc_x64_custom.dll!wxFrame::wxFrame(wxWindow * parent=0x0000000000000000, int id=-1, const wxString & title={...}, const wxPoint & pos={...}, const wxSize & size={...}, long style=541072960, const wxString & name={...}) Line 33 C++ Symbols loaded.
minimal.exe!MyFrame::MyFrame(const wxString & title={...}) Line 142 C++ Symbols loaded.
Hit 3: again returns true
> wxmsw330u_core_vc_x64_custom.dll!wxMSWImpl::ShouldUseDarkMode() Line 133 C++ Symbols loaded.
wxmsw330u_core_vc_x64_custom.dll!wxMSWDarkMode::AllowForWindow(HWND__ * hwnd=0x00000000001a0946, const wchar_t * themeName=0x00007fffc46b2008, const wchar_t * themeId=0x0000000000000000) Line 258 C++ Symbols loaded.
wxmsw330u_core_vc_x64_custom.dll!wxWindow::MSWCreate(const wchar_t * wclass=0x000001e01ad34750, const wchar_t * title=0x000001e01ad104d0, const wxPoint & pos, const wxSize & size={...}, unsigned long style=47120384, unsigned long extendedStyle=0) Line 4101 C++ Symbols loaded.
wxmsw330u_core_vc_x64_custom.dll!wxTopLevelWindowMSW::CreateFrame(const wxString & title, const wxPoint & pos={...}, const wxSize & size) Line 423 C++ Symbols loaded.
wxmsw330u_core_vc_x64_custom.dll!wxTopLevelWindowMSW::Create(wxWindow * parent=0x0000000000000000, int id=-1, const wxString & title={...}, const wxPoint & pos={...}, const wxSize & size, long style=541072960, const wxString & name={...}) Line 499 C++ Symbols loaded.
wxmsw330u_core_vc_x64_custom.dll!wxFrame::Create(wxWindow * parent, int id, const wxString & title, const wxPoint & pos={...}, const wxSize & size={...}, long style=541072960, const wxString & name={...}) Line 123 C++ Symbols loaded.
wxmsw330u_core_vc_x64_custom.dll!wxFrame::wxFrame(wxWindow * parent=0x0000000000000000, int id=-1, const wxString & title={...}, const wxPoint & pos={...}, const wxSize & size={...}, long style=541072960, const wxString & name={...}) Line 33 C++ Symbols loaded.
minimal.exe!MyFrame::MyFrame(const wxString & title={...}) Line 142 C++ Symbols loaded.
Hit 4: again returns true
> wxmsw330u_core_vc_x64_custom.dll!wxMSWImpl::ShouldUseDarkMode() Line 133 C++ Symbols loaded.
wxmsw330u_core_vc_x64_custom.dll!wxMSWDarkMode::EnableForTLW(HWND__ * hwnd=0x00000000001a0946) Line 239 C++ Symbols loaded.
wxmsw330u_core_vc_x64_custom.dll!wxTopLevelWindowMSW::Create(wxWindow * parent=0x0000000000000000, int id=-1, const wxString & title={...}, const wxPoint & pos={...}, const wxSize & size, long style=541072960, const wxString & name={...}) Line 516 C++ Symbols loaded.
wxmsw330u_core_vc_x64_custom.dll!wxFrame::Create(wxWindow * parent, int id, const wxString & title, const wxPoint & pos={...}, const wxSize & size={...}, long style=541072960, const wxString & name={...}) Line 123 C++ Symbols loaded.
wxmsw330u_core_vc_x64_custom.dll!wxFrame::wxFrame(wxWindow * parent=0x0000000000000000, int id=-1, const wxString & title={...}, const wxPoint & pos={...}, const wxSize & size={...}, long style=541072960, const wxString & name={...}) Line 33 C++ Symbols loaded.
minimal.exe!MyFrame::MyFrame(const wxString & title={...}) Line 142 C++ Symbols loaded.
Hit 5: now returns false
> wxmsw330u_core_vc_x64_custom.dll!wxMSWImpl::ShouldUseDarkMode() Line 133 C++ Symbols loaded.
wxmsw330u_core_vc_x64_custom.dll!wxSystemSettingsNative::GetColour(wxSystemColour index=wxSYS_COLOUR_APPWORKSPACE) Line 103 C++ Symbols loaded.
wxmsw330u_core_vc_x64_custom.dll!wxFrame::Create(wxWindow * parent, int id, const wxString & title, const wxPoint & pos={...}, const wxSize & size={...}, long style=541072960, const wxString & name={...}) Line 126 C++ Symbols loaded.
wxmsw330u_core_vc_x64_custom.dll!wxFrame::wxFrame(wxWindow * parent=0x0000000000000000, int id=-1, const wxString & title={...}, const wxPoint & pos={...}, const wxSize & size={...}, long style=541072960, const wxString & name={...}) Line 33 C++ Symbols loaded.
minimal.exe!MyFrame::MyFrame(const wxString & title={...}) Line 142 C++ Symbols loaded.
Hit 6: now returns true
> wxmsw330u_core_vc_x64_custom.dll!wxMSWImpl::ShouldUseDarkMode() Line 133 C++ Symbols loaded.
wxmsw330u_core_vc_x64_custom.dll!wxMSWDarkMode::HandleMenuMessage(__int64 * result=0x000000be0feff6c8, wxWindow * w=0x000001e01ad168b0, unsigned int nMsg=70, unsigned __int64 wParam=0, __int64 lParam=816311171584) Line 479 C++ Symbols loaded.
wxmsw330u_core_vc_x64_custom.dll!wxFrame::MSWWindowProc(unsigned int message=70, unsigned __int64 wParam=0, __int64 lParam=816311171584) Line 841 C++ Symbols loaded.
wxmsw330u_core_vc_x64_custom.dll!wxWndProc(HWND__ * hWnd=0x00000000001a0946, unsigned int message=70, unsigned __int64 wParam=0, __int64 lParam=816311171584) Line 2980 C++ Symbols loaded.
[External Code] Annotated Frame
wxmsw330u_core_vc_x64_custom.dll!wxFrame::InternalSetMenuBar() Line 393 C++ Symbols loaded.
wxmsw330u_core_vc_x64_custom.dll!wxFrame::AttachMenuBar(wxMenuBar * menubar=0x000001e01ad2b090) Line 389 C++ Symbols loaded.
wxmsw330u_core_vc_x64_custom.dll!wxFrameBase::SetMenuBar(wxMenuBar * menubar=0x000001e01ad2b090) Line 679 C++ Symbols loaded.
minimal.exe!MyFrame::MyFrame(const wxString & title) Line 175 C++ Symbols loaded.
The only difference compared to the debug build I noticed were missing calls to wxMSWDarkMode::IsActive() (which in the debug build precede wxMSWImpl::ShouldUseDarkMode() call), but I guess this single line function was optimized out.
I still have no explanation for this oddity but seeing as I was able to reproduce it on two non-identical computers, I don't think I am seeing things...
BTW @vadz, I noticed that wxMSWDarkMode::EnableForTLW() does not use wxMSWDarkMode::IsActive() but directly calls wxMSWImpl::ShouldUseDarkMode(): Is that by design?
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()
Unfortunately I can't reproduce this, and I'm completely baffled as to how this can happen.
If I debug this, I can see that the code calls into ShouldAppsUseDarkMode() inside uxtheme.dll, as expected, and this function is pretty trivial:
_ShouldAppsUseDarkMode@0:
72A322F0 mov eax,dword ptr [g_preferredAppMode (72A68BA0h)]
72A322F5 cmp eax,3
72A322F8 je _ShouldAppsUseDarkMode@0+18h (72A32308h)
72A322FA cmp eax,2
72A322FD je _ShouldAppsUseDarkMode@0+1Bh (72A3230Bh)
72A322FF cmp byte ptr [g_isSystemAppModeLight (72A674C0h)],0
72A32306 je _ShouldAppsUseDarkMode@0+1Bh (72A3230Bh)
72A32308 xor al,al
72A3230A ret
72A3230B mov al,1
72A3230D ret
and both g_preferredAppMode and g_isSystemAppModeLight are 1 in light mode, so the function returns 0. And as this function is inside the system DLL, it can't be affected by how the application code is compiled, so the only explanation is that the values of these variables are somehow different in the release build for you.
I do use a (much) older Windows version, so I'll have to retry this when I update to your version or greater, but right now I don't know what to do here...
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()
Firstly, I repeat that I do understand that the issue description looks like a crazy man rambling, as I cannot see any logical explanation for this.
But I was able to reproduce it on another computer (which should rule out the the issue being machine-specific):
When I trace the code with MSVC (I know nothing about assembler, so the following may be irrelevant), I can see that eax is 0 when ShouldAppsUseDarkMode() returns false as expected (during the first call):

but a random-looking largish number (different each call) when it is not. Second call:

Third call:

—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()
Just to be clear, I don't doubt that you see it, but I don't understand how is this possible.
Could you please try to step in into the indirect call (call qword ptr [wxMSWImpl::ShouldAppsUseDarkMode]) and see where does it go? Does it look like the short function shown above or something completely different? Without symbols (which you can easily configure MSVS to use) you won't see the function name, but could you please check if it's at least in the correct DLL (uxtheme) or does it jump to some completely different place?
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()
Could you please try to step in into the indirect call (
call qword ptr [wxMSWImpl::ShouldAppsUseDarkMode]) and see where does it go?
It looks like this (and it is inside uxtheme.dll):
00007FF9B46C9E10 mov ecx,dword ptr [g_preferredAppMode (07FF9B47434A4h)]
00007FF9B46C9E16 xor al,al
00007FF9B46C9E18 cmp ecx,3
00007FF9B46C9E1B je ShouldAppsUseDarkMode+1Ah (07FF9B46C9E2Ah)
00007FF9B46C9E1D cmp ecx,2
00007FF9B46C9E20 je ShouldAppsUseDarkMode+1Ch (07FF9B46C9E2Ch)
00007FF9B46C9E22 cmp byte ptr [g_isSystemAppModeLight (07FF9B47417A0h)],al
00007FF9B46C9E28 je ShouldAppsUseDarkMode+1Ch (07FF9B46C9E2Ch)
00007FF9B46C9E2A ret
00007FF9B46C9E2B int 3
00007FF9B46C9E2C mov al,1
00007FF9B46C9E2E ret
Comparing our disassemblies, it seems you used a 32-bit build (code offsets, registers, and yours ShouldAppsUseDarkMode() has a leading underscore)? I cannot reproduce the issue in a 32-bit build (cmake -G "Visual Studio 17 2022" -A Win32 ...), sorry for not trying a 32-build before.
As for 64-bit MSVC build, I have also:
/O1, /O2, and /Ox; but not with /Od.
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()
OK, thanks, I am almost sure I see it and the error is completely obvious in hindsight, as usual, really sorry for wasting your time :-(
Anyhow, as the disassembly clearly shows (and not only yours in 64 bits, but mine in 32 bits too), this function returns bool as it only sets AL register and leaves arbitrary junk in the rest of EAX. But I (wrongly) declared it as returning BOOL, which is int.
I've created #23186 to fix this, could you please confirm that it does solve the problem for you?
And thanks once again for reporting it!
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()
Looking at the return type was my first thought, but I was sure it was declared as bool (and hence I was surprised to see the function prototype displayed as returning int (i.e., BOOL) by the debugger). I vividly misremembered this because it was the first time I saw bool used in Win32 API, I must have confused it with another similar code.
This also explains why I could not reproduce in a minimal Win32 application (where I used bool), which made me question my sanity.
Sorry for not noticing this myself.
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()
Closed #23169 as completed via 93c6551.
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()