#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<Ptr *>(&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<Ptr *>(&m_lfW)
+ : reinterpret_cast<Ptr *>(&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 *);
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*);
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)();
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,
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);
}