Click here to Skip to main content
15,888,113 members
Articles / Programming Languages / C++

Adding XP Visual Style Support to OWNERDRAW Controls using HTHEME Wrapper

Rate me:
Please Sign up or sign in to vote.
4.86/5 (4 votes)
29 Jan 20023 min read 156.9K   999   25   36
A wrapper class to use the visual styles APIs available in Windows XP
In this article, you will see a wrapper class for the HTHEME handle used in connection with the Visual Styles API available in Windows XP. The class is heavily based on the CVisualStylesXP class by David Yuheng Zhao.

Introduction

This is a wrapper class for the HTHEME handle used in connection with the Visual Styles API available in Windows XP. This article and the code provided is heavily based on Add XP Visual Style Support in OWNERDRAW Controls by David Yuheng Zhao. To understand this article and the code provided, I strongly recommend that you read that article.

The class provided is based on the CVisualStylesXP class described in the previously mentioned article, indeed several portions of the code are copied directly, but some major conceptual changes have been made. Instead of the handle to the uxtheme.dll being a normal member of the CVisualStylesXP class, it has been made static in CXPTheme, resulting in a single load per application. Also, the function pointers returned by GetProcAddress are cached in static function pointers, which are then used in subsequent calls. In the situation where the DLL is not available, the addresses of special failure member methods providing reasonable responses are assigned to these static function pointers instead. This results in a highly optimized execution.

A more significant difference for the users of this class is the fact that CXPTheme wraps the HTHEME handle. This provides a more object-oriented approach to using the API. Unless specifically needed, the user never interacts directly with the HTHEME handle. Instead, the handle is kept in a member variable and internally applied where necessary. The handle is closed in the class destructor. The class provides several constructors and overloaded operators for ease of use.

The API functions not directly related to a HTHEME are created as static member methods, not requiring an instance of the class. In addition, the static member method IsAvailable has been added for a specific check on whether the current platform supports theming. In most cases, it will suffice to use the IsAppThemed API function because the corresponding special failure method will return FALSE on platforms which do not provide theming, signalling "old-style" drawing.

How to Use

The class is very easy to use. First, you need to include the header, preferably in stdafx.h and add the CPP file in the project.

C++
#include "XPTheme.h"

Then you can either create a local CXPTheme variable where needed, or add it as a class member of the control.

C++
CXPTheme theme(GetSafeHwnd(), L"TOOLBAR");
theme.DrawBackground(pDC->GetSafeHdc(), TP_BUTTON, TS_CHECKED, &rc, 0);
// the handle is closed when the variable goes out of scope.

To make your application work under all Windows versions, you should do something like this:

C++
#ifdef _XPTHEME_H_
    if (CXPTheme::IsAppThemed())
    {
        CXPTheme theme(GetSafeHwnd(), L"TOOLBAR");
        theme.DrawBackground(pDC->GetSafeHdc(), TP_BUTTON, TS_CHECKED, &rc, 0);
    }
    else
    {
#endif
        pDC->DrawEdge(....);
#ifdef _XPTHEME_H_
    }
#endif

The preferred way to use this class would probably be to make it a control member variable which is initialized in the control constructor. Once the control is deleted, the CXPTheme variable will be deleted as well, and the handle closed safely. The control should handle the new WM_THEMECHANGED message, and close and reopen the theme using the Close and Open member methods. Actually, the Open method could be used alone, because an open handle is closed automatically before opening a new one.

C++
case WM_THEMECHANGED:
    m_theme.Close();
    m_theme.Open(GetSafeHwnd(), L"TOOLBAR");
    break;

The download includes the class itself in addition to three header files taken from the Platform SDK. These are necessary to compile the code without the latest SDK. For the same reason, a typedef for the WM_THEMECHANGED message has been added to the XPTheme.h file.

History

  • 30th January, 2002: Initial version

License

This article has no explicit license attached to it, but may contain usage terms in the article text or the download files themselves. If in doubt, please contact the author via the discussion board below.

A list of licenses authors might use can be found here.


Written By
Web Developer
Norway Norway
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralI want use xp visual style in the IE toolbar Pin
AllenDog11-Dec-04 11:10
AllenDog11-Dec-04 11:10 
GeneralTheme change kills XP look on CDialogBar Pin
pixelgrease18-Sep-03 11:05
pixelgrease18-Sep-03 11:05 
GeneralParts and States Pin
Armen Hakobyan25-Aug-02 7:17
professionalArmen Hakobyan25-Aug-02 7:17 
GeneralRe: Parts and States Pin
Zorglab11-Jan-03 5:16
Zorglab11-Jan-03 5:16 
GeneralBS_ICON + Theme in Windows XP Pin
15-Mar-02 4:41
suss15-Mar-02 4:41 
GeneralI don't really understand... Pin
28-Feb-02 6:51
suss28-Feb-02 6:51 
GeneralRe: I don't really understand... Pin
Paul A. Howes28-Feb-02 7:17
Paul A. Howes28-Feb-02 7:17 
GeneralRe: I don't really understand... Pin
28-Feb-02 8:05
suss28-Feb-02 8:05 
GeneralRe: I don't really understand... Pin
Paul A. Howes28-Feb-02 10:16
Paul A. Howes28-Feb-02 10:16 
GeneralNasty Bug! Pin
Swinefeaster8-Feb-02 21:21
Swinefeaster8-Feb-02 21:21 
After incorporating this wonderful wrapper into my project, I found this rather nasty bug that occurred only in release mode on Windows 2000. The app would crash horribly upon startup, just after it made a call to CXPTheme::Open(). After throwing out all my house furniture out through the windows in frustration, I finally figured out what was happening, and the realization left a confused smile on my face.

So what was going on? Since Windows 2000 does not support themes, the GetProc() call to "OpenThemeData" would of course fail, and a pointer to the OpenThemeDataFail() static member would be used. This would be called, and as soon as this call returned, the this pointer came back as garbage. Now there are two possibilities why this was happening:

1. My optimization setting of "Inline Any Suitable" was inlining that function, though the compiler should have detected that its address was being taken and not have inlined it in the first place.

2. The static member OpenThemeDataFail() uses a different calling convention.

Now I haven't figured out completely why, but what I did was add __stdcall to the declaration of OpenThemeDataFail() and everything worked happily! Perhaps the author might have some insight...? Check it out, this is what I did:

Original:
static HTHEME OpenThemeDataFail(HWND , LPCWSTR )
{return NULL;}

Modified:
static HTHEME __stdcall OpenThemeDataFail(HWND , LPCWSTR )
{return NULL;}

Oh, one more thing.... the 3rd constructor of CXPTheme() forgets to set the dll handle member to NULL before calling Open(), which also calls Close(). It should be defined as:

CXPTheme::CXPTheme(HWND hwnd, LPCWSTR pszClassList)
{
m_hTheme = NULL;
Open(hwnd, pszClassList);
}

Cheers,

swinefeaster

Check out Aephid Photokeeper, the powerful digital
photo album solution at www.aephid.com.
GeneralThanks for input Pin
Pål K Tønder10-Feb-02 21:19
Pål K Tønder10-Feb-02 21:19 
GeneralRe: Thanks for input Pin
Swinefeaster10-Feb-02 21:38
Swinefeaster10-Feb-02 21:38 
GeneralRe: Thanks for input Pin
Pål K Tønder11-Feb-02 2:17
Pål K Tønder11-Feb-02 2:17 
GeneralI Just Want To Draw A Stupid Button! Pin
Swinefeaster7-Feb-02 12:37
Swinefeaster7-Feb-02 12:37 
GeneralRe: I Just Want To Draw A Stupid Button! Pin
Pål K Tønder7-Feb-02 20:47
Pål K Tønder7-Feb-02 20:47 
GeneralWP_MINBUTTON Pin
Swinefeaster6-Feb-02 22:10
Swinefeaster6-Feb-02 22:10 
GeneralRe: WP_MINBUTTON Pin
Pål K Tønder6-Feb-02 23:27
Pål K Tønder6-Feb-02 23:27 
GeneralRe: WP_MINBUTTON Pin
Andrey197331-Jan-03 7:11
Andrey197331-Jan-03 7:11 
GeneralNon Owner Draw Buttons and Controls Pin
Swinefeaster6-Feb-02 21:03
Swinefeaster6-Feb-02 21:03 
GeneralRe: Non Owner Draw Buttons and Controls Pin
Swinefeaster6-Feb-02 23:17
Swinefeaster6-Feb-02 23:17 
QuestionWorks on all versions of Windows or Not? Pin
Swinefeaster5-Feb-02 20:58
Swinefeaster5-Feb-02 20:58 
AnswerRe: Works on all versions of Windows or Not? Pin
Pål K Tønder5-Feb-02 21:43
Pål K Tønder5-Feb-02 21:43 
GeneralRe: Works on all versions of Windows or Not? Pin
Swinefeaster6-Feb-02 9:14
Swinefeaster6-Feb-02 9:14 
GeneralRe: Works on all versions of Windows or Not? Pin
Pål K Tønder6-Feb-02 20:43
Pål K Tønder6-Feb-02 20:43 
GeneralA demo project wanted Pin
yellowine31-Jan-02 3:29
yellowine31-Jan-02 3:29 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.