 |
BorlandTalk.com Borland discussion newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
JD Guest
|
Posted: Wed Aug 24, 2005 6:00 pm Post subject: XP Theming |
|
|
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
|
Posted: Wed Aug 24, 2005 7:22 pm Post subject: Re: XP Theming |
|
|
"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
|
Posted: Wed Aug 24, 2005 8:00 pm Post subject: Re: XP Theming |
|
|
"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
|
Posted: Wed Aug 24, 2005 8:31 pm Post subject: Re: XP Theming |
|
|
"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
|
Posted: Wed Aug 24, 2005 9:08 pm Post subject: Re: XP Theming |
|
|
"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
|
Posted: Wed Aug 24, 2005 9:25 pm Post subject: Re: XP Theming |
|
|
"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
|
Posted: Thu Aug 25, 2005 1:58 am Post subject: Re: XP Theming |
|
|
"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
|
Posted: Thu Aug 25, 2005 6:27 am Post subject: Re: XP Theming |
|
|
"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?
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 |
|
 |
|
|
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
|
|