From 3120eccfe2b3f02207c4d14f14f76dfd319db309 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sat, 30 Oct 2010 23:50:22 +0000 Subject: [PATCH] Fix confusion with LOGFONT{A,W} parameters to MSW GetTheme[Sys]Font(). Change the signature of GetThemeFont() and GetThemeSysFont() methods of wxUxThemeEngine to take an artificial wxUxThemeFont::Ptr type instead of LOGFONT which allows the broken code to compile correctly and even work in Unicode builds but crashed in ANSI ones under Windows Vista/7 as these functions expect a LOGFONTW and not LOGFONTA even in non-Unicode build under these systems. This generalizes the previous fix/workaround for the same problem in wxStaticBox so remove it now and use wxUxThemeFont both there and in wxMenuItem to avoid crashes when using owner-drawn menus in ANSI build. Closes #12364. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@65955 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- include/wx/msw/uxtheme.h | 72 ++++++++++++++++++++++++++++++++++++++-- src/msw/menuitem.cpp | 6 ++-- src/msw/statbox.cpp | 24 ++------------ 3 files changed, 76 insertions(+), 26 deletions(-) diff --git a/include/wx/msw/uxtheme.h b/include/wx/msw/uxtheme.h index aa03f8522e..934fbb2949 100644 --- a/include/wx/msw/uxtheme.h +++ b/include/wx/msw/uxtheme.h @@ -17,6 +17,74 @@ #include "wx/msw/private.h" // we use GetHwndOf() #include "wx/msw/uxthemep.h" +// Amazingly, GetThemeFont() and GetThemeSysFont() functions use LOGFONTA under +// XP but LOGFONTW (even in non-Unicode build) under later versions of Windows. +// If we declare them as taking LOGFONT below, the code would be able to +// silently pass LOGFONTA to them in ANSI build and would crash at run-time +// under Windows Vista/7 because of a buffer overrun (LOGFONTA being smaller +// than LOGFONTW expected by these functions). If we we declare them as taking +// LOGFONTW, the code wouldn't work correctly under XP. So we use a special +// wxUxThemeFont class to encapsulate this and intentionally change the LOGFONT +// output parameters of the theme functions to take it instead. + +class wxUxThemeFont +{ +public: + // Trivial default ctor. + wxUxThemeFont() { } + + // Just some unique type. + struct Ptr { }; + +#if wxUSE_UNICODE + // In Unicode build we always use LOGFONT anyhow so this class is + // completely trivial. + Ptr *GetPtr() { return reinterpret_cast(&m_lfW); } + const LOGFONTW& GetLOGFONT() { return m_lfW; } +#else // !wxUSE_UNICODE + // Return either LOGFONTA or LOGFONTW pointer as required by the current + // Windows version. + Ptr *GetPtr() + { + return UseLOGFONTW() ? reinterpret_cast(&m_lfW) + : reinterpret_cast(&m_lfA); + } + + // This method returns LOGFONT (i.e. LOGFONTA in ANSI build and LOGFONTW in + // Unicode one) which can be used with other, normal, Windows or wx + // functions. Internally it may need to transform LOGFONTW to LOGFONTA. + const LOGFONTA& GetLOGFONT() + { + if ( UseLOGFONTW() ) + { + // Most of the fields are the same in LOGFONTA and LOGFONTW so just + // copy everything by default. + memcpy(&m_lfA, &m_lfW, sizeof(m_lfA)); + + // But the face name must be converted from Unicode. + WideCharToMultiByte(CP_ACP, 0, m_lfW.lfFaceName, -1, + m_lfA.lfFaceName, sizeof(m_lfA.lfFaceName), + NULL, NULL); + } + + return m_lfA; + } + +private: + static bool UseLOGFONTW() + { + return wxGetWinVersion() >= wxWinVersion_Vista; + } + + LOGFONTA m_lfA; +#endif // wxUSE_UNICODE/!wxUSE_UNICODE + +private: + LOGFONTW m_lfW; + + wxDECLARE_NO_COPY_CLASS(wxUxThemeFont); +}; + typedef HTHEME (__stdcall *PFNWXUOPENTHEMEDATA)(HWND, const wchar_t *); typedef HRESULT (__stdcall *PFNWXUCLOSETHEMEDATA)(HTHEME); typedef HRESULT (__stdcall *PFNWXUDRAWTHEMEBACKGROUND)(HTHEME, HDC, int, int, const RECT *, const RECT *); @@ -39,7 +107,7 @@ typedef HRESULT (__stdcall *PFNWXUGETTHEMEBOOL)(HTHEME, int, int, int, BOOL *); typedef HRESULT (__stdcall *PFNWXUGETTHEMEINT)(HTHEME, int, int, int, int *); typedef HRESULT (__stdcall *PFNWXUGETTHEMEENUMVALUE)(HTHEME, int, int, int, int *); typedef HRESULT (__stdcall *PFNWXUGETTHEMEPOSITION)(HTHEME, int, int, int, POINT *); -typedef HRESULT (__stdcall *PFNWXUGETTHEMEFONT)(HTHEME, HDC, int, int, int, LOGFONT *); +typedef HRESULT (__stdcall *PFNWXUGETTHEMEFONT)(HTHEME, HDC, int, int, int, wxUxThemeFont::Ptr *); typedef HRESULT (__stdcall *PFNWXUGETTHEMERECT)(HTHEME, int, int, int, RECT *); typedef HRESULT (__stdcall *PFNWXUGETTHEMEMARGINS)(HTHEME, HDC, int, int, int, RECT *, MARGINS *); typedef HRESULT (__stdcall *PFNWXUGETTHEMEINTLIST)(HTHEME, int, int, int, INTLIST*); @@ -50,7 +118,7 @@ typedef COLORREF(__stdcall *PFNWXUGETTHEMESYSCOLOR)(HTHEME, int); typedef HBRUSH (__stdcall *PFNWXUGETTHEMESYSCOLORBRUSH)(HTHEME, int); typedef BOOL (__stdcall *PFNWXUGETTHEMESYSBOOL)(HTHEME, int); typedef int (__stdcall *PFNWXUGETTHEMESYSSIZE)(HTHEME, int); -typedef HRESULT (__stdcall *PFNWXUGETTHEMESYSFONT)(HTHEME, int, LOGFONT *); +typedef HRESULT (__stdcall *PFNWXUGETTHEMESYSFONT)(HTHEME, int, wxUxThemeFont::Ptr *); typedef HRESULT (__stdcall *PFNWXUGETTHEMESYSSTRING)(HTHEME, int, wchar_t *, int); typedef HRESULT (__stdcall *PFNWXUGETTHEMESYSINT)(HTHEME, int, int *); typedef BOOL (__stdcall *PFNWXUISTHEMEACTIVE)(); diff --git a/src/msw/menuitem.cpp b/src/msw/menuitem.cpp index bc5bebea68..fb02feaadb 100644 --- a/src/msw/menuitem.cpp +++ b/src/msw/menuitem.cpp @@ -367,9 +367,9 @@ void MenuDrawData::Init() Offset = -14; - wxNativeFontInfo fontInfo; - theme->GetThemeSysFont(hTheme, TMT_MENUFONT, &fontInfo.lf); - Font = wxFont(fontInfo); + wxUxThemeFont themeFont; + theme->GetThemeSysFont(hTheme, TMT_MENUFONT, themeFont.GetPtr()); + Font = wxFont(themeFont.GetLOGFONT()); Theme = true; diff --git a/src/msw/statbox.cpp b/src/msw/statbox.cpp index 1058f381b9..2047e8bd4c 100644 --- a/src/msw/statbox.cpp +++ b/src/msw/statbox.cpp @@ -430,11 +430,7 @@ void wxStaticBox::PaintForeground(wxDC& dc, const RECT& rc) wxUxThemeHandle hTheme(this, L"BUTTON"); if ( hTheme ) { - // GetThemeFont() expects its parameter to be LOGFONTW and not - // LOGFONTA even in ANSI programs and will happily corrupt - // memory after the struct end if we pass a LOGFONTA (which is - // smaller) to it! - LOGFONTW lfw; + wxUxThemeFont themeFont; if ( wxUxThemeEngine::Get()->GetThemeFont ( hTheme, @@ -442,24 +438,10 @@ void wxStaticBox::PaintForeground(wxDC& dc, const RECT& rc) BP_GROUPBOX, GBS_NORMAL, TMT_FONT, - (LOGFONT *)&lfw + themeFont.GetPtr() ) == S_OK ) { -#if wxUSE_UNICODE - // ok, no conversion necessary - const LOGFONT& lf = lfw; -#else // !wxUSE_UNICODE - // most of the fields are the same in LOGFONTA and LOGFONTW - LOGFONT lf; - memcpy(&lf, &lfw, sizeof(lf)); - - // but the face name must be converted - WideCharToMultiByte(CP_ACP, 0, lfw.lfFaceName, -1, - lf.lfFaceName, sizeof(lf.lfFaceName), - NULL, NULL); -#endif // wxUSE_UNICODE/!wxUSE_UNICODE - - font.Init(lf); + font.Init(themeFont.GetLOGFONT()); if ( font ) selFont.Init(hdc, font); } -- 2.45.2