Click here to Skip to main content
Click here to Skip to main content

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

By , 27 Aug 2003
 

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)

About the Author

Don Kackman
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

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralGetSchemaInfo() Function is not found. Compilation ErrormemberPrasanna Bhat9-Nov-10 7:41 
Hi,
 
I am getting below error when I compile it. Please somebody help.
1>------ Build started: Project: System.Windows.Forms.Themes, Configuration: Debug Win32 ------
1>Build started 11/9/2010 11:28:21 PM.
1>InitializeBuildStatus:
1> Touching "Debug\System.Windows.Forms.Themes.unsuccessfulbuild".
1>ClCompile:
1> All outputs are up-to-date.
1>cl : Command line warning D9035: option 'clr:oldsyntax' has been deprecated and will be removed in a future release
1> PropTable.cpp
1>PropTable.cpp(25): error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
1>PropTable.cpp(25): error C2143: syntax error : missing ';' before '*'
1>PropTable.cpp(25): error C2065: 'pPropTable' : undeclared identifier
1>PropTable.cpp(25): error C2227: left of '->pPropTable' must point to class/struct/union/generic type
1> type is ''unknown-type''
1>PropTable.cpp(25): error C3861: 'GetSchemaInfo': identifier not found
1>PropTable.cpp(30): error C2227: left of '->iPropCount' must point to class/struct/union/generic type
1> type is ''unknown-type''
1>PropTable.cpp(30): error C2228: left of '.pszName' must have class/struct/union
1>PropTable.cpp(30): error C3861: 'GetSchemaInfo': identifier not found
1>PropTable.cpp(30): fatal error C1903: unable to recover from previous error(s); stopping compilation
1> StatesCollection.cpp
1> TmSchema.h is obsolete. Please include vssym32.h instead.
1>StatesCollection.cpp(36): error C2440: 'initializing' : cannot convert from '__const_Char_ptr' to 'wchar_t __pin *'
1> Conversion loses qualifiers
1> ThemeInfo.cpp
1> TmSchema.h is obsolete. Please include vssym32.h instead.
1>ThemeInfo.cpp(54): error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
1>ThemeInfo.cpp(118): error C2440: 'initializing' : cannot convert from '__const_Char_ptr' to 'wchar_t __pin *'
1> Conversion loses qualifiers
1> ThemeItemCollection.cpp
1>ThemeItemCollection.cpp(106): error C2440: 'initializing' : cannot convert from '__const_Char_ptr' to 'wchar_t __pin *'
1> Conversion loses qualifiers
1> VisualStylesXP.cpp
1> TmSchema.h is obsolete. Please include vssym32.h instead.
1> Generating Code...
1>
1>Build FAILED.
1>
1>Time Elapsed 00:00:07.32
2>------ Build started: Project: ManagedThemeExplorer, Configuration: Debug Any CPU ------
2>Build started 11/9/2010 11:28:29 PM.
2>K:\WINDOWS\Microsoft.NET\Framework\v4.0.30128\Microsoft.Common.Targets(1143,9): error MSB3204: The project file "..\System.Windows.Forms.Themes\System.Windows.Forms.Themes.vcproj" is in the ".vcproj" file format, which MSBuild no longer supports. Please convert the project by opening it in the Visual Studio IDE or running the conversion tool, or use MSBuild 3.5 or earlier to build it.
2>
2>Build FAILED.
2>
2>Time Elapsed 00:00:00.04
========== Build: 0 succeeded, 2 failed, 0 up-to-date, 0 skipped ==========
GeneralRe: GetSchemaInfo() Function is not found. Compilation ErrormemberDon Kackman9-Nov-10 7:52 
All of this was written on XP against VS.NET 2003(5?) and much has changed since then. The key thing to note is this
TmSchema.h is obsolete. Please include vssym32.h instead.
 
With Windows Vista the built in themeing was changed dramatically, including the bits that set up the data and structures that specify the various parts of the UI that can be themed (that's part of what tmchema.h does).
 
There are also going to be issues with the version of VS.NET and the MC++ compiler you are using. That is I believe where these are coming from:
error C2440: 'initializing' : cannot convert from '__const_Char_ptr' to 'wchar_t __pin *'
 
So unfortunately this code is very out of date. I made a start at updating awhile ago but didn't get very far before other things distracted me Smile | :)
10 PRINT "Software is hard. - D. Knuth"
20 GOTO 10

GeneralRe: GetSchemaInfo() Function is not found. Compilation ErrormemberPrasanna Bhat10-Nov-10 7:22 
Thank you for the immediate reply. I installed the VC 2003 and compiled the setup. Its compiling fine. Thanks again.
 
I am looking to change the windows theme at global level. I mean changing the WindowsClassic.Theme to Luna.Theme and In reverse way also.
. Is there any possibility to do that.
 
I am able to apply the Luna.msstyle programetically. But I am not able to apply the Luna.Theme or WindowsClassic.Theme Programetically. I need as assistance from you, if know.
 
--
Thanks & Regards,
Prasanna Bhat
GeneralRe: GetSchemaInfo() Function is not found. Compilation ErrormemberDon Kackman10-Nov-10 11:00 
Applying the theme is outside of what this code does. This was all about looking into the current theme and so those visual element can be applied to custom controls etc.
 
I'm afraid I don't know how to programatically change the OS theme.
10 PRINT "Software is hard. - D. Knuth"
20 GOTO 10

QuestionNo binaries?memberTheAlas7-Nov-10 10:53 
Hey,
 
Looks like a very useful tool when working with uxtheme, but no binaries? Frown | :( I can't compile it, and I'd just need it to browse various theme elements as the demo looks neat Smile | :) , basically I don't really need the wrapper itself - just the basic knowhow from source. The demo looks useful so it would be great to have an exe.
 
Cheers.
 
BS
AnswerRe: No binaries?memberDon Kackman10-Nov-10 11:01 
I'm afraid the code is VS/NET 2003 and associated compilers. I don't have those around any more.
 
It sounds like Prasanna Bhat in the post right above this thread got it built. Maybe he can get you binaries.
10 PRINT "Software is hard. - D. Knuth"
20 GOTO 10

QuestionVisual Studio 2005 and 2008 port - completedmemberCodeWizard19519-Apr-08 3:59 
I've completed a Visual Studio 2005 and 2008 port of this project. I am in the process of adding xml documentation to the project, using help from MSDN to aid the documentation of the UxTheme calls. I have used only new syntax. It is no longer required to use the oldSyntax compiler setting.
 
I have not been able to find a way to contact Mr. Don Kackman. I need to know if he minds if I post my updates to his code. I know this project is old, but I think there may be a few programmers still interested in using this wrapper. I needed it for a custom button tutorial I am working on.
AnswerRe: Visual Studio 2005 and 2008 port - completedmemberjfoegen12-May-09 8:22 
Where is the port of the code?
GeneralRe: Visual Studio 2005 and 2008 port - completedmemberCodeWizard195113-May-09 10:42 
A Managed C++ Wrapper Around the Windows XP Theme API - Part 2[^]
 
CodeWiz51
 
-- Life is not a spectator sport. I came to play.
My Web Site, Blog & Wiki

AnswerRe: Visual Studio 2005 and 2008 port - completedmemberDon Kackman12-May-09 8:31 
Send me the ported code and I'll post it with the article.
 
dkackman_2000
at
yahoo
dot
com
 
10 PRINT Software is hard. - D Knuth
20 GOTO 10

GeneralRe: Visual Studio 2005 and 2008 port - completedmemberCodeWizard195113-May-09 10:38 
This message is over a year old. We've talked since then by email. The code is in the article: A Managed C++ Wrapper Around the Windows XP Theme API - Part 2[^]
 
Gene
 
CodeWiz51
 
-- Life is not a spectator sport. I came to play.
My Web Site, Blog & Wiki

GeneralRe: Visual Studio 2005 and 2008 port - completedmemberDon Kackman13-May-09 11:31 
Hehe you are right. Laugh | :laugh: I looked at jfoegen's post and the Apr 08 of the original and thought Apr 09.
 
Thanks for reposting the link.
 
10 PRINT Software is hard. - D Knuth
20 GOTO 10

GeneralRe: Visual Studio 2005 and 2008 port - completedmemberCodeWizard195113-May-09 11:37 
I was about to send you the code when I thought: Wait a minute, didn't I publish that article ? Laugh | :laugh:
 
I think we've all slept since April '08. Add in a couple of brewskis and the past seems so fuzzy now.
 
Gene
 
CodeWiz51
 
-- Life is not a spectator sport. I came to play.
My Web Site, Blog & Wiki

QuestionCompile of C++ code in XP Platformmemberkk_kumaraswamy27-May-07 20:06 
hi,
 
i wanna know compile of C++ code on Windows XP Platform
 
With Regards
KK
GeneralAutomated C++ WrappermemberRapidXLL_NET14-Sep-06 23:31 

If you are interested in running your C++ library within a C# / .NET application or within Excel worksheet functions, then let RapidXLL automatically build your wrappers.
 
Visit http://www.RapidXLL.net
 
RapidXLL automatically wraps C/C++ code into Excel Add-Ins (XLL) and Managed C++ .NET Libraries.

GeneralGreat WorkmemberSameers (theAngrycodeR )15-Aug-06 12:05 
Great work though, but I think, there should be a compiled DLL too. Since many peoples may not have VC installed. I personally will have to isntall VC and then test this.
 
BTW, I am aimed to use this in Outlook Add-in (.NET based). Before this, I tried to use EnableVisualStyle property of .NET framework but it causes crashes in the Outlook (if two level dialog opens). Do you think it will work fine?
 
I will test though!
 

 
Need custom software? Contact DevelopersINN[^]
Need to add reminders for your Outlook emails? Try Outlook Personal Assistant[^]

QuestionVS 2005 Compile Issuesmemberserialc0d328-Jul-06 2:29 
First of all this assembly seems to be exactly what I need although I can't get it compiled after converting it to VS 2005.
 
Getting Errors:
C2440(cannot convert from __cont_Char_ptr to wchar_t__pin), C4430 (missing type specifier - int assumed. C++ does not support default-int)
 
Seems to be just data type conversion issues although I can seem to get rid of them. Confused | :confused:
 
Anyone have an ideas on these? I know they just sound like conversion errors although I think there might be something bigger? Unsure | :~
 
Rose | [Rose] Rose | [Rose] Rose | [Rose] for the first response! Smile | :)
 
Thanks all!

 
serialc0d3
"Lost in the c0d3"

AnswerRe: VS 2005 Compile Issuesmemberserialc0d328-Jul-06 6:15 
heh, OK.. I am getting lazy in my old age.. Laugh | :laugh:
 
I just compiled it in 1.1 (2003).. no probs.. Cool | :cool:
 
Strange the diff between 2.0 and 1.1..
 
Rose | [Rose] for me?
 
serialc0d3
"Lost in the c0d3"

GeneralUpgrade to .Net 2 compile problemmemberfewfewfewfgwew4-Mar-06 16:12 
Hi,
 
I try to upgrade this wonderful lib to .Net 2 (VS 2005), but I receive following issues:
1. wchar_t __pin* class_name = PtrToStringChars( className );
cannot convert from '__const_Char_ptr' to 'wchar_t __pin *'
Fixed it by "const wchar_t __pin* class_name = PtrToStringChars( className );"
 
but after this problem fixed, I still couldn't get the program to run.
 
Please help
QuestionRe: Upgrade to .Net 2 compile problemmembertheoneno125-Mar-06 19:34 
i had the same problem in here, after i fixed the const wchar_t__pin8 class_name = PtrToStringChars(classname) i am having another problem when loading any control into the project.
it says :
could not load file or assembly System.Window.Forms.Themes, Version = 1.0.22276.1656, Culture = neutral, PublicKeyToken=7f2b58f4359288ef' or one of its dependencies. Strong name validation failed. (Exception from HRESULT: 0x8013141A)
i think it has something to do with the themes namesapce, i tried to reallocate the assembly file that was created but it didn't work
 
please advice Cry | :((
AnswerRe: Upgrade to .Net 2 compile problemmemberThierry Parent18-Jun-06 3:20 
Hi.
 
I got the same problem about the Strong name validation.
Did you fix the problem ?
Thierry
GeneralRe: Upgrade to .Net 2 compile problemmemberAulofee21-Jun-06 6:28 
We faced the same problem... and solved it.
 
In .Net2, the old attribute AssemblyKeyFile has been deprecated (it was found in the AssemblyInfo.cs files). The place where you specify the key file to use to sign an assembly is nowadays the project property page. Yet, this location is nearly hidden - at least far less visible - for c++ projects compared to c# projects.
 
By specifying the snk file at the right place (and removing the old attribute), the C++ Theme wrapper will compile and be loaded fine.
 
For c# project: go to Menu Project > properties > Configuration Properties (in the treeview) > Signing tab > check the "Sign the assembly" check box + specify the location of the file.
 
For c++ projects : go to Menu Project > properties > Configuration Properties (in the treeview) > Linker > Advanced > Key file (on the right of the window, not in the tree) and there, enter the path+filename of your snk file.
 
Lionel
 
Lionel Cuir,
Associate
Aulofee IT Security & Supervision Systems (http://www.aulofee.com)
* Security and Log correlation
* IT Asset Management and real-time Inventory
* Reporting
* Network Cartography

GeneralRe: Upgrade to .Net 2 compile problemmemberOlivier REIX26-Jul-06 3:33 
Thank you so much. Your post just solved my problem !
GeneralRe: Upgrade to .Net 2 compile problemmemberChaosofmankind30-Oct-06 10:51 
Should this be done on the Theme wrapper itself? Or the application it is being used in. I have tried both and it does not seem to work either way Frown | :(
QuestionMeta Data?memberKHadden30-Nov-05 8:48 
Is it possible to extract metadata about the parts? For instance background color(s). There are many elements on my forms, like splitters, that I want to reflect the current theme. The .net versions of these work fine, so I don't want to roll my own just to make them reflect the theme colors.

 
KHadden...

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

Permalink | Advertise | Privacy | Mobile
Web01 | 2.6.130617.1 | Last Updated 28 Aug 2003
Article Copyright 2003 by Don Kackman
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid