Click here to Skip to main content
15,867,991 members
Articles / Programming Languages / C#
Article

A Managed C++ Wrapper Around the Windows XP Theme API

Rate me:
Please Sign up or sign in to vote.
4.97/5 (31 votes)
27 Aug 2003CPOL5 min read 307.1K   5.5K   72   69
Using the XP Theme API safely on any OS from C#

Sample image

Introduction

The Managed UxTheme assembly is a .NET wrapper around Windows XP's Theme API. It can be used safely from C#, on any Windows platform that supports the .NET framework. In addition to exposing the UxTheme API, it also exposes the static data in TmSchema.h (part of the Platform SDK) that is used to define what window classes can be themed, the parts of those classes, and the states that each part may have a custom look for.

Background

Windows XP uses a C-style DLL to expose its theme functionality named UxTheme.dll (the "Ux" stands for User eXperience). At my day job, I am working on a couple of .NET custom controls written in C#. Of course one of the requirements for these controls is that they use Windows XP themes when appropriate, and mirror the user's current theme settings.

The problem with UxTheme.dll is that it is only available on Windows XP, so any P/Invoke code that tries to use it directly will fail on other versions of Windows. Pierre Arnaud has written a C++ wrapper DLL that can be safely called via P/Invoke on any .NET capable version of Windows. His implementation uses David Y. Zhao's nice little C++ wrapper class that dynamically links to UxTheme.dll, while also providing safe fail-thru implementations of each method, if it can't load the UxTheme library.

I like Pierre's solution and started out by using it. It didn't however provide me with the level of functionality that I need from UxTheme.dll. My next thought was to extend his work and continue using P/Invoke from C#. I have however been looking for an excuse to do something more than the "Hello World!" in Managed C++, and this seemed like the perfect opportunity.

This implementation also uses David's wrapper class (as do almost all of the examples of XP theme related code on CodeProject. It really is a nice piece of work!).

Implementation

There are two discrete parts of this assembly from the outside perspective. The first is the UxTheme class. This class provides a managed wrapper around an HTHEME handle. It exposes all of the methods on the UxTheme DLL that takes an HTHEME as instance method. Methods that do not take a theme handle are exposed as static. Any thing it is possible to do using the DLL's API should be possible through this class.

Parallel to this is an object hierarchy that wraps the property table data created by TmSchema.h and Schemadefs.h. These two files are part of the platform SDK and define the data model for what parts of the Windows UI can be theme-ed.

This object hierarchy starts with the ThemeInfo class. This class contains some simple meta-data about the current theme, but also contains a collection of WindowThemes. A WindowTheme represents data about the parts of a particular window class. The WindowTheme class has a collection of ThemeParts, and ThemePartStates.

A ThemePart represents a discrete part of a window class. The down button for instance, is part of the ScrollBar window class.

Each WindowTheme and ThemePart can have 0 to n states. ThemePartStates are things like normal, disabled, or hot. The WindowTheme class has an UxTheme property that can be used to get an instance of the UxTheme class specific for the window class. ThemePart and ThemePartStates also contain some instance methods so that they can be rendered directly into a graphics context.

The UxTheme class can be used without the ThemeInfo hierarchy, but the hierarchy does put a more OO face on the whole thing.

Using the code

Using the code is pretty straightforward. All of the classes are in the namespace System.Windows.Forms.Themes. The only public ally creatable class is ThemeInfo. To drill your way down through the window class, their parts and states, create an instance of ThemeInfo and start looking through its collection of WindowThemes on down.

You can get an instance of UxTheme, either from an instance of WindowTheme, or by calling either of the static methods UxTheme::OpenTheme or UxTheme::GetWindowTheme.

Make sure that you look at UxTheme::IsAppThemed in you code before trying to use any of the other methods of UxTheme. This will tell you whether the current OS supports themes and if so whether it is currently themed. And don't forget, that this can change throughout the lifetime of your application, because the user can turn off themes at any time.

The assembly does have a strong name, so you can put it in the GAC if you want.

The demo project contains a re-implementation of David's Theme Explorer application, written in C# and using the managed API. It also include a slight re-work of the TabPage compatible controls that Pierre has made available. They are included merely as a demonstration of how this assembly can be used from custom control implementations.

Points of interest

Managed C++ DLLs have some interesting constraints about entry points. Since this DLL uses the C-Runtime it is a mixed mode DLL. It is compiled with the /NOENTRY linker flag. Assemblies linked with this flag do no have an explicit entry point, preventing the initialization of any static data aside from simple, integral types. It would be nice to be able to use the CVisualStylesXp class as a static instance, but because the runtime does not initialize it, this isn't possible.

Each instance of UxTheme creates a member pointer to an instance of the CVisualStylesXp class. UxThemes's static methods create an instance of this class locally. The result of this is a lot of calls to LoadLibrary and FreeLibrary. Luckily Windows keeps a reference count on dynamically loaded DLLs, so this shouldn't pose a significant performance hit.

Be that as may, it is something that bugs me about my implementation. If anybody's got a good way to load and free the UxTheme DLL just once, and avoid creating so many instances of the C++ wrapper class I'd love to hear it. MSDN recommends implementing explicit Initialize and Deinitialize methods, but I don't like forcing that on users of this assembly.

History

  • Version 1 - Initial release
  • 08/26/2003
    • Bug fixes
    • Some reorganization in the API

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Team Leader Starkey Laboratories
United States United States
The first computer program I ever wrote was in BASIC on a TRS-80 Model I and it looked something like:
10 PRINT "Don is cool"
20 GOTO 10

It only went downhill from there.

Hey look, I've got a blog

Comments and Discussions

 
GeneralGetSchemaInfo() Function is not found. Compilation Error Pin
Prasanna Bhat9-Nov-10 7:41
professionalPrasanna Bhat9-Nov-10 7:41 
GeneralRe: GetSchemaInfo() Function is not found. Compilation Error Pin
Don Kackman9-Nov-10 7:52
Don Kackman9-Nov-10 7:52 
GeneralRe: GetSchemaInfo() Function is not found. Compilation Error Pin
Prasanna Bhat10-Nov-10 7:22
professionalPrasanna Bhat10-Nov-10 7:22 
GeneralRe: GetSchemaInfo() Function is not found. Compilation Error Pin
Don Kackman10-Nov-10 11:00
Don Kackman10-Nov-10 11:00 
QuestionNo binaries? Pin
Bojan Sala7-Nov-10 10:53
professionalBojan Sala7-Nov-10 10:53 
AnswerRe: No binaries? Pin
Don Kackman10-Nov-10 11:01
Don Kackman10-Nov-10 11:01 
QuestionVisual Studio 2005 and 2008 port - completed Pin
Gene OK9-Apr-08 3:59
Gene OK9-Apr-08 3:59 
AnswerRe: Visual Studio 2005 and 2008 port - completed Pin
jfoegen12-May-09 8:22
jfoegen12-May-09 8:22 
GeneralRe: Visual Studio 2005 and 2008 port - completed Pin
Gene OK13-May-09 10:42
Gene OK13-May-09 10:42 
AnswerRe: Visual Studio 2005 and 2008 port - completed Pin
Don Kackman12-May-09 8:31
Don Kackman12-May-09 8:31 
GeneralRe: Visual Studio 2005 and 2008 port - completed Pin
Gene OK13-May-09 10:38
Gene OK13-May-09 10:38 
GeneralRe: Visual Studio 2005 and 2008 port - completed Pin
Don Kackman13-May-09 11:31
Don Kackman13-May-09 11:31 
GeneralRe: Visual Studio 2005 and 2008 port - completed Pin
Gene OK13-May-09 11:37
Gene OK13-May-09 11:37 
QuestionCompile of C++ code in XP Platform Pin
kk_kumaraswamy27-May-07 20:06
kk_kumaraswamy27-May-07 20:06 
GeneralAutomated C++ Wrapper Pin
RapidXLL_NET14-Sep-06 23:31
RapidXLL_NET14-Sep-06 23:31 
GeneralGreat Work Pin
Sameers Javed15-Aug-06 12:05
Sameers Javed15-Aug-06 12:05 
QuestionVS 2005 Compile Issues Pin
serialc0d328-Jul-06 2:29
serialc0d328-Jul-06 2:29 
AnswerRe: VS 2005 Compile Issues Pin
serialc0d328-Jul-06 6:15
serialc0d328-Jul-06 6:15 
GeneralUpgrade to .Net 2 compile problem Pin
fewfewfewfgwew4-Mar-06 16:12
fewfewfewfgwew4-Mar-06 16:12 
QuestionRe: Upgrade to .Net 2 compile problem Pin
theoneno125-Mar-06 19:34
theoneno125-Mar-06 19:34 
AnswerRe: Upgrade to .Net 2 compile problem Pin
Thierry Parent18-Jun-06 3:20
Thierry Parent18-Jun-06 3:20 
GeneralRe: Upgrade to .Net 2 compile problem Pin
Aulofee21-Jun-06 6:28
Aulofee21-Jun-06 6:28 
GeneralRe: Upgrade to .Net 2 compile problem Pin
Olivier REIX26-Jul-06 3:33
Olivier REIX26-Jul-06 3:33 
GeneralRe: Upgrade to .Net 2 compile problem Pin
Chaosofmankind30-Oct-06 10:51
Chaosofmankind30-Oct-06 10:51 
QuestionMeta Data? Pin
KHadden30-Nov-05 8:48
KHadden30-Nov-05 8:48 

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.