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

How to accurately detect if an application is theme-enabled?

By , 1 Jun 2005
 

Fig. 1 : System wide and app-specific themes enabled

Fig. 2 : System wide themes enabled, app-specific themes disabled

Fig. 3 : System wide themes disabled. (App-specific doesn't matter)

Overview

When you develop custom controls that work differently depending on whether the application has themes enabled or not, you need to detect whether the currently running application is using themes or not. MSDN lists two functions IsAppThemed and IsThemeActive and I list below snippets from their documentation :-

IsAppThemed Function - Reports whether the current application's user interface displays using visual styles.
IsThemeActive Function - Tests if a visual style for the current application is active.

You'd think that all you need to do is to use one or both of these functions, wouldn't you? Guess what? On XP (even SP2) both these functions return TRUE if your system wide themes setting is enabled. Thus any system that's using an XP styled theme will always have these two functions returning TRUE.

I googled around and didn't find anything worthwhile. I saw a posting from Jeff Partch (MVP) who suggested calling GetModuleHandle on comctl32.dll and comparing this module handle with the handle returned by calling GetClassLongPtr on a known control handle with the GCLP_HMODULE flag. While I didn't actually try that out, I thought it'd be easier to call DllGetVersion on comctl32.dll and check if the version is 6 or greater.

The IsThemed function

The code lavishly uses LoadLibrary/GetProcAddress to avoid a dependency on the PSDK (the code now compiles on the default installation of VC++ 6).

#pragma once

#include "stdafx.h"
#include <Shlwapi.h>

BOOL IsThemed()
{
    BOOL ret = FALSE;
    OSVERSIONINFO ovi = {0};
    ovi.dwOSVersionInfoSize = sizeof ovi;
    GetVersionEx(&ovi);
    if(ovi.dwMajorVersion==5 && ovi.dwMinorVersion==1)
    {
        //Windows XP detected
        typedef BOOL WINAPI ISAPPTHEMED();
        typedef BOOL WINAPI ISTHEMEACTIVE();
        ISAPPTHEMED* pISAPPTHEMED = NULL;
        ISTHEMEACTIVE* pISTHEMEACTIVE = NULL;
        HMODULE hMod = LoadLibrary(_T("uxtheme.dll"));
        if(hMod)
        {
            pISAPPTHEMED = reinterpret_cast<ISAPPTHEMED*>(
                GetProcAddress(hMod,_T("IsAppThemed")));
            pISTHEMEACTIVE = reinterpret_cast<ISTHEMEACTIVE*>(
                GetProcAddress(hMod,_T("IsThemeActive")));
            if(pISAPPTHEMED && pISTHEMEACTIVE)
            {
                if(pISAPPTHEMED() && pISTHEMEACTIVE())                
                {                
                    typedef HRESULT CALLBACK DLLGETVERSION(DLLVERSIONINFO*);
                    DLLGETVERSION* pDLLGETVERSION = NULL;

                    HMODULE hModComCtl = LoadLibrary(_T("comctl32.dll"));
                    if(hModComCtl)
                    {
                        pDLLGETVERSION = reinterpret_cast<DLLGETVERSION*>(
                            GetProcAddress(hModComCtl,_T("DllGetVersion")));
                        if(pDLLGETVERSION)
                        {
                            DLLVERSIONINFO dvi = {0};
                            dvi.cbSize = sizeof dvi;
                            if(pDLLGETVERSION(&dvi) == NOERROR )
                            {
                                ret = dvi.dwMajorVersion >= 6;
                            }
                        }
                        FreeLibrary(hModComCtl);                    
                    }
                }
            }
            FreeLibrary(hMod);
        }
    }    
    return ret;
}

Using the code

if(IsThemed())
    m_bThemed = true;
else
    m_bThemed = false;

History

  • June 02, 2005 - Article first published

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

About the Author

Nish Sivakumar
United States United States
Member
Nish is a real nice guy who has been writing code since 1990 when he first got his hands on an 8088 with 640 KB RAM. Originally from sunny Trivandrum in India, he has been living in various places over the past few years and often thinks it’s time he settled down somewhere.
 
Nish has been a Microsoft Visual C++ MVP since October, 2002 - awfully nice of Microsoft, he thinks. He maintains an MVP tips and tricks web site - www.voidnish.com where you can find a consolidated list of his articles, writings and ideas on VC++, MFC, .NET and C++/CLI. Oh, and you might want to check out his blog on C++/CLI, MFC, .NET and a lot of other stuff - blog.voidnish.com.
 
Nish loves reading Science Fiction, P G Wodehouse and Agatha Christie, and also fancies himself to be a decent writer of sorts. He has authored a romantic comedy Summer Love and Some more Cricket as well as a programming book – Extending MFC applications with the .NET Framework.
 
Nish's latest book C++/CLI in Action published by Manning Publications is now available for purchase. You can read more about the book on his blog.
 
Despite his wife's attempts to get him into cooking, his best effort so far has been a badly done omelette. Some day, he hopes to be a good cook, and to cook a tasty dinner for his wife.

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   
QuestionIs there a reason to check IsAppThemed / IsThemeActive first?memberpeterchen24 Mar '09 - 7:11 
Shouldn't the check for COMMCTL32 dll version be enough?
 

GeneralSuggestion: No need to check comctl32.dll versionmemberSumit Kapoor2 Aug '06 - 20:38 

Code is very nice and I would like to appreciate you effort.
 
But, I think, There is no need to check comctl32.dll version.
 
we should only use :
----
--
----
if(pISAPPTHEMED() && pISTHEMEACTIVE())
{
return TRUE;
}
---
-
As in my case comctl32.dll version is 5, so it is not getting right result, even theme is still selected and Active.
 
So I have to use code without using Comctl32.dll version info.
 
Smile | :)

 
Never consider anything impossible before trying to solve that..---Sumit Kapoor---

GeneralRe: Suggestion: No need to check comctl32.dll versionmemberAnil K P10 Jun '07 - 23:54 
Nishant,
I used your function in an MFC Application which ran on a Windows XP machine and I got it's return value as 0, which means FALSE. Isn't it so? I debugged and found that the statement
ret = dvi.dwMajorVersion >= 6;
assigns 0 to ret (dvi.dwMajorVersion = 5 and 5>=6 is FALSE). So, as Sumit said I just used
if(pISAPPTHEMED() && pISTHEMEACTIVE())
{
return TRUE;
}

and now the return value of the function is TRUE.
What should be done so that I can use the original code and get the desired output?
GeneralRe: Suggestion: No need to check comctl32.dll versionmemberKeith Worden17 Jul '08 - 2:40 
It IS necessary to check the comctl32.dll version as Nishant explained in his article. IsAppThemed seems to return true whether the application allows themes (i.e. includes a manifest file) or not. When a manifest file is not included the comctl32 version is 5.something when included it's 6.something. I have testing this on Win 2000, XP and Vista and found Nishant's code to work perfectly.
GeneralUnicodememberWarren D Stevens13 Nov '05 - 2:34 
To get this to build under UNICODE, I removed the _T() macros from the calls to GetProcAddress, as the function doesn't seem to have a wide-string version.
 
For Example:
 
I changed:
GetProcAddress(hMod, _T("IsAppThemed"));
to:
GetProcAddress(hMod, "IsAppThemed");
 
Warren
GeneralRe: UnicodestaffNishant Sivakumar13 Nov '05 - 2:38 
Yep, I had blogged on this a while ago, but forgot to update this article Sigh | :sigh:
 
GetProcAddress in Unicode builds [^]
 
Thanks Warren
Nish
GeneralMaking code Vista (or later) friendlymemberWarren D Stevens11 Nov '05 - 7:21 
Nice Code!!!! Writing this kind of stuff is very unpleasant - thanks for taking the time to write it, and share it.
 
The line:
if(ovi.dwMajorVersion==5 && ovi.dwMinorVersion==1)
looks like it won't work on anything other than XP.
 
According to this page on MSDN:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/sysinfo/base/osversioninfo_str.asp[^]
 
Vista (aka Longhorn) is version 6.0
Windows Server 2003 is 5.2 (2003 isn't really of interest to me)
 
And on this page on MSDN:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/sysinfo/base/getversionex.asp[^]
 
there is some example code sitting there, which seems to suggest the right test should be:
 
bIsWindowsXPorLater =
( (osvi.dwMajorVersion > 5) ||
( (osvi.dwMajorVersion == 5) && (osvi.dwMinorVersion >= 1) );

 

Warren
GeneralRe: Making code Vista (or later) friendlymemberYongchun8 Jan '06 - 0:28 
bool Is_WinXP_or_Later()
{
OSVERSIONINFOEX osvi;
DWORDLONG dwlConditionMask = 0;
 
// Initialize the OSVERSIONINFOEX structure.
 
ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
osvi.dwMajorVersion = 5;
osvi.dwMinorVersion = 1;
 
// Initialize the condition mask.
 
VER_SET_CONDITION( dwlConditionMask, VER_MAJORVERSION,
VER_GREATER_EQUAL );
VER_SET_CONDITION( dwlConditionMask, VER_MINORVERSION,
VER_GREATER_EQUAL );

// Perform the test.
BOOL res=::VerifyVersionInfo(
&osvi,
VER_MAJORVERSION | VER_MINORVERSION,
dwlConditionMask);
return res?true:false;
}
 

Mike J http://www.tablane.com

GeneralRe: Making code Vista (or later) friendlymemberWarren D Stevens11 Jan '06 - 5:21 
Yes, that's a much more elegant way of doing it !
 
Warren
GeneralRe: Making code Vista (or later) friendlymemberKeith Worden17 Jul '08 - 2:37 
Simplest way is to just omit the version check - if it's a version of Windows which doesn't support themes (i.e. pre XP) then uxtheme.dll won't be there. Omitting the version check means it will work for all future versions as well.
GeneralRe: Making code Vista (or later) friendlymemberWarren Stevens17 Jul '08 - 17:21 
Keith Worden wrote:
Simplest way is to just omit the version check

 

Simple? Yes. Work? Not so much.
 
The whole point of GetProcAddress (and all of that) is to be able to load on an older version of Windows. If you call a function that requires (say) Windows XP, and try to load your app on Windows 2000, it will not work.
GeneralRe: Making code Vista (or later) friendlymemberKeith Worden18 Jul '08 - 0:11 
As I said in my reply the uxtheme dll won't be there so LoadLibrary will not work so the code won't get to GetProcAddress.
GeneralIsAppThemed returns FALSE for a Windows XP (Modified) themesussBrian KS6 Oct '05 - 6:52 
However, IsThemeActive() returns TRUE. In this case, it's safe to use an OR "||", instead of "&&":
 
if ( pISAPPTHEMED() && pISTHEMEACTIVE() )
 
To:
 
if ( pISAPPTHEMED() || pISTHEMEACTIVE() )
 
Sigh | :sigh:
Questionxp+ ?memberUnruled Boy2 Jun '05 - 2:51 
well, how about 2003/longhorn?
 
Regards,
unruledboy@hotmail.com
AnswerRe: xp+ ?staffNishant Sivakumar2 Jun '05 - 5:42 
Unruled Boy wrote:
well, how about 2003/longhorn?
 
I haven't tried it out on 2003, but I sure hope the two APIs work as expected on it. And Longhorn is way way into the future Smile | :)

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.130523.1 | Last Updated 2 Jun 2005
Article Copyright 2005 by Nish Sivakumar
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid