BorlandTalk.com Forum Index BorlandTalk.com
Borland discussion newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

XP Theming

 
Post new topic   Reply to topic    BorlandTalk.com Forum Index -> C++ Builder (Native API)
View previous topic :: View next topic  
Author Message
JD
Guest





PostPosted: Wed Aug 24, 2005 6:00 pm    Post subject: XP Theming Reply with quote




I developed code to determine if an application is running on a
system with XP and if Theming is enabled. In addition, the test
attempts to open and close a theming handle. My problem is that
the test produces different results under 2 different
conditions. More specifically, the determination portion of the
code always runs correctly. It's the opening of the theme
handle (OpenThemeData) that sometimes fails.

OpenThemeData is prototyped as:

HANDLE OpenThemeData(HWND, LPCWSTR );

and I traced the problem to the HWND parameter.

If I run my code from a button click, using the main form's
Handle for the HWND, OpenThemeData succeedes. However, I need
to run it from within a subclassed TStringGrid. When I use the
grid's Handle, OpenThemeData fails (returns NULL). A call to
GetLastError consistantly returns:

Error Code : 2147943568

and if I pump that code into SysErrorMessage, it returns:

"Element Not Found."

Since I can't find anything on this, I've assumed that it's
meaningless or not useful.

In an effort to work around this problem, I've substituted
using the grid's Handle with using the Application's Handle and
the main form's Handle but I get the same result as when I use
the grid's Handle.

The only way that I've been able to get it to work is to use
AllocateHWnd and pass in the resulting HWND instead. This
doesn't seem right to me since it works using the main form's
handle in one case but not the other. I even used PostMessage
to delay running the test until I was sure that everything had
been constructed so that I could duplicate the application
state as with the button click.

I'd appreciate any comments.

~ JD

Back to top
Remy Lebeau (TeamB)
Guest





PostPosted: Wed Aug 24, 2005 7:22 pm    Post subject: Re: XP Theming Reply with quote




"JD" <nospam (AT) nospam (DOT) com> wrote


Quote:
I need to run it from within a subclassed TStringGrid. When I
use the grid's Handle, OpenThemeData fails (returns NULL).

According to MSDN:

"Call OpenThemeData and pass the hwnd of the control you wish to apply
visual styles to and a class list that describes the control's type. The
classes are defined in Tmschema.h. OpenThemeData returns an HTHEME handle,
but if the visual style manager is disabled or the current visual style does
not supply specific information for a given control, the function returns
NULL."

Quote:
A call to GetLastError consistantly returns:

Error Code : 2147943568

and if I pump that code into SysErrorMessage, it returns:

"Element Not Found."

Exactly. You are trying to load a theme element that does not actually
exist for TStringGrid.

Quote:
Since I can't find anything on this, I've assumed that it's
meaningless or not useful.

You assume incorrectly.

Quote:
In an effort to work around this problem, I've substituted
using the grid's Handle with using the Application's Handle and
the main form's Handle but I get the same result as when I use
the grid's Handle.

Then you are not using it properly to begin with. Please show your actual
code.


Gambit



Back to top
JD
Guest





PostPosted: Wed Aug 24, 2005 8:00 pm    Post subject: Re: XP Theming Reply with quote




"Remy Lebeau (TeamB)" <no.spam (AT) no (DOT) spam.com> wrote:
Quote:

[...] You are trying to load a theme element that does not
actually exist for TStringGrid.

This makes sense. However, MSDN provided an example where
"ToolButton" was passed into OpenThemeData to be used for
the 'cells' of some sort of calander object. I don't believe
that OpenThemeData is type checking the HWND parameter and
if it is, then why would it accept the handle from AllocateHWnd?

Quote:
but I get the same result as when I use the grid's Handle.

Then you are not using it properly to begin with. Please show your actual
code.

That's all gone now. However, I used GetParentForm to get the
handle of the main form in one case. In another, I used the
Owner to cast to the main form type to get the handle and
finally I used PostMessage to delay the code until Application->MainForm
was valid. All handles failed when used with OpenThemeData.

~ JD


Back to top
Remy Lebeau (TeamB)
Guest





PostPosted: Wed Aug 24, 2005 8:31 pm    Post subject: Re: XP Theming Reply with quote


"JD" <nospam (AT) nospam (DOT) com> wrote


Quote:
This makes sense. However, MSDN provided an example
where "ToolButton" was passed into OpenThemeData to be
used for the 'cells' of some sort of calander object.

That works because a Calendar object actually does have a ToolButton element
defined for its theme.

Quote:
I don't believe that OpenThemeData is type checking the HWND
parameter

Yes, it does. That is the only way for it to know whether the class list is
valid or not for the specified window.

Quote:
if it is, then why would it accept the handle from AllocateHWnd?

I cannot answer that because you have yet to show your actual code like I
asked you to.


Gambit



Back to top
JD
Guest





PostPosted: Wed Aug 24, 2005 9:08 pm    Post subject: Re: XP Theming Reply with quote


"Remy Lebeau (TeamB)" <no.spam (AT) no (DOT) spam.com> wrote:
Quote:

if it is, then why would it accept the handle from AllocateHWnd?

I cannot answer that because you have yet to show your
actual code like I asked you to.

I thought you wanted to see what code didn't work.

In the main form's ctor:

TMyComponent *pComponent = new TMyComponent( this );
if( pComponent->Succeeded ) ShowMessage("Determing Theming Succeeded.");
else ShowMessage(pComponent->ThemeError);

//-------------------------------------------------------------
#ifndef Unit2H
#define Unit2H
//-------------------------------------------------------------
#include <Classes.hpp>
#include <shlwapi.h>
//-------------------------------------------------------------
class TMyComponent : public TComponent
{
protected:
virtual void __fastcall WndProc( TMessage &Message );
private:
HWND FHandle;
bool FSucceeded;
AnsiString FThemeError;
public:
__fastcall TMyComponent(TComponent* Owner);
__fastcall ~TMyComponent();
__property bool Succeeded = { read = FSucceeded };
__property AnsiString ThemeError = { read = FThemeError };
};
//-------------------------------------------------------------
#endif


//-------------------------------------------------------------
#include <basepch.h>
#pragma hdrstop

#include "Unit2.h"
#pragma package(smart_init)

//-------------------------------------------------------------
__fastcall TMyComponent::TMyComponent(TComponent* Owner) : TComponent(Owner)
{
FSucceeded = false;
FThemeError = "";
FHandle = NULL;
if( !ComponentState.Contains(csDesigning) )
{
FHandle = AllocateHWnd( WndProc );
WORD MajorVersion = 0;
HINSTANCE hComCtl32 = ::LoadLibrary( "ComCtl32.dll" );
if( hComCtl32 )
{
DLLGETVERSIONPROC lpDllGetVersion = (DLLGETVERSIONPROC) ::GetProcAddress( hComCtl32, "DllGetVersion" );
if( lpDllGetVersion )
{
DLLVERSIONINFO dvi = { sizeof(DLLVERSIONINFO), 0 };
if( SUCCEEDED(lpDllGetVersion(&dvi)) ) MajorVersion = dvi.dwMajorVersion;
}
::FreeLibrary( hComCtl32 );
}
else FThemeError = "LoadLibrary::ComCtl32 Failed.";
if( MajorVersion > 5 )
{
HINSTANCE hUxTheme = ::LoadLibrary( "UxTheme.dll" );
if( hUxTheme )
{
typedef BOOL WINAPI (*DLLISTHEMEACTIVE)();
DLLISTHEMEACTIVE IsThemeActive = (DLLISTHEMEACTIVE) ::GetProcAddress( hUxTheme, "IsThemeActive" );
if( IsThemeActive )
{
if( IsThemeActive() )
{
typedef HANDLE HTHEME; typedef HTHEME WINAPI (*DLLOPENTHEMEDATA)(HWND, LPCWSTR ); DLLOPENTHEMEDATA OpenThemeData = (DLLOPENTHEMEDATA) ::GetProcAddress( hUxTheme, "OpenThemeData" );
if( OpenThemeData )
{
HTHEME hTheme = OpenThemeData(FHandle, L"Button");
if( hTheme )
{
typedef HRESULT WINAPI (*DLLCLOSETHEMEDATA)( HTHEME ); DLLCLOSETHEMEDATA CloseThemeData = (DLLCLOSETHEMEDATA) ::GetProcAddress( hUxTheme, "CloseThemeData" );
if( CloseThemeData ) { CloseThemeData( hTheme ); FSucceeded = true; } else FThemeError = "GetProcAddress::CloseThemeData failed.";
}
else FThemeError.sprintf("Call to OpenThemeData failed.nGetLastError : %unttt0x%08XnSysErrorMessage : %s", ::GetLastError(), ::GetLastError(), SysErrorMessage(::GetLastError()) );
}
else FThemeError = "GetProcAddress::OpenThemeData failed.";
}
else FThemeError = "Theming is not active.";
}
else FThemeError = "GetProcAddress::IsThemeActive failed.";
::FreeLibrary( hUxTheme );
}
else FThemeError = "LoadLibrary::UxTheme failed.";
}
else FThemeError.sprintf("ComCtl32 Major Version too small : %d.", MajorVersion);
}
}
//-------------------------------------------------------------
__fastcall TMyComponent::~TMyComponent()
{
if( FHandle ) DeallocateHWnd( FHandle );
}
//-------------------------------------------------------------
void __fastcall TMyComponent::WndProc( TMessage &Message )
{
Message.Result = DefWindowProc( FHandle, Message.Msg, Message.WParam, Message.LParam );
}
//-------------------------------------------------------------

~ JD


Back to top
Remy Lebeau (TeamB)
Guest





PostPosted: Wed Aug 24, 2005 9:25 pm    Post subject: Re: XP Theming Reply with quote


"JD" <nospam (AT) nospam (DOT) com> wrote


Quote:
I thought you wanted to see what code didn't work.

No, that is not the code I wanted to see. I wanted to see your original
StringGrid code that started this discussion in the first place.

Quote:
HINSTANCE hComCtl32 = ::LoadLibrary( "ComCtl32.dll" );

Use GetModuleHandle() instead:

HINSTANCE hComCtl32 = ::GetModuleHandle( "COMCTL32" );

Better yet, why bother checking ComCtl32.dll at all? You are only using it
to decide whether to check for UxTheme.dll, which you can do without first
checking ComCtl32.dll at all.


Gambit



Back to top
JD
Guest





PostPosted: Thu Aug 25, 2005 1:58 am    Post subject: Re: XP Theming Reply with quote


"Remy Lebeau (TeamB)" <no.spam (AT) no (DOT) spam.com> wrote:
Quote:

I thought you wanted to see what code didn't work.

No, that is not the code I wanted to see. I wanted to see your original
StringGrid code that started this discussion in the first place.

It's *exactly* what I posted except that the object was derived
from TStringGrid and instead of using AllocateHWnd, I passed
the grid's Handle to OpenThemeData.

I haven't had a chance to test it yet but I'm of the opinion
that the HWND is a moot point as far as the theme drawing is
concerned because the drawing functions that I'm looking at
want an HDC and a RECT. I'm thinking that as long as I get it
opened, I can draw in the fashion as determined by the LPCWSTR
parameter.

Quote:
HINSTANCE hComCtl32 = ::LoadLibrary( "ComCtl32.dll" );

Use GetModuleHandle() instead:

I did initially but because I had problems, I reverted to what
*I* knew to be true. The win32 help was a bit fuzzy to me.

Quote:
Better yet, why bother checking ComCtl32.dll at all? You
are only using it to decide whether to check for UxTheme.dll
which you can do without first checking ComCtl32.dll at all.

Not true. UxTheme.dll can be present and theming enabled but
you still need to check the Major version for ComCtl32 because
to do theming, a manifest file must still exist. If it does
not exist, ComCtl32 returns 5 as the major version number
instead of 6.

~ JD


Back to top
Remy Lebeau (TeamB)
Guest





PostPosted: Thu Aug 25, 2005 6:27 am    Post subject: Re: XP Theming Reply with quote


"JD" <nospam (AT) nospam (DOT) com> wrote


Quote:
It's *exactly* what I posted except that the object was derived
from TStringGrid and instead of using AllocateHWnd, I passed
the grid's Handle to OpenThemeData.

Well, your code is in the constructor, where the inherited Handle is not
valid to begin with. What happens if you delay your code until after the
StringGrid's Handle is actually available?

Quote:
Not true.

Yes true.

Quote:
UxTheme.dll can be present and theming enabled but you still need
to check the Major version for ComCtl32

No, you do not.

Quote:
because to do theming, a manifest file must still exist.

Exactly. Since you are dynamically loading the theming functions at
runtime, if no manifest exists then the OS will load ComCtrl32.dll v5.x
instead of v6.x, and thus GetProcAddress() will fail to find the functions.
You can test for that condition without doing any version checking at all.


Gambit



Back to top
Display posts from previous:   
Post new topic   Reply to topic    BorlandTalk.com Forum Index -> C++ Builder (Native API) All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.