Selectively enabling Visual Styles with SetWindowTheme

  • Thread starter Thread starter Robert Jacobson
  • Start date Start date
R

Robert Jacobson

Hi,

I'm develing a COM add-in for Microsoft Word XP that displays a form. I'd
like to have the form display using the Windows XP theme. However, neither
using a manifest nor calling Application.EnableVisualStyles does the trick.
(EnableVisualStyles works but massive instability, probably because the
system is trying to theme the Word application itself.)

I'm now trying to selectively enable the themes for just my form, or just
certain elements on my form, by using the SetWindowTheme api. My
understanding is that SetWindowTheme doesn't need a manifest to work. (MSDN
isn't particularly clear.)

Herfried posted an article that discussed using this function with VB6:
http://www.activevb.de/tutorials/tut_xpstyles/xpstyles.html

Here's a (poorly) translated version:
http://translate.google.com/transla...ivevb.de/tutorials/tut_xpstyles/xpstyles.html
(You gotta love using the "Communist manifesto" in Visual Basic. <g>)

I created a test WinForms app that contains just a simple form with a
button. In the code below, I'm trying to theme the button. The function is
returning a 0 (success?) but still appears in the classic style. It happens
regardless of whether the button has "Standard" or "System" FlatStyle.

Any suggestions?

Thanks,
Robert Jacobson



Private Declare Function ActivateWindowTheme Lib "uxtheme" Alias
"SetWindowTheme" ( _
ByVal hWnd As IntPtr, _
Optional ByVal pszSubAppName As Integer = 0, _
Optional ByVal pszSubIdList As Integer = 0) _
As Integer

Private Declare Function DeactivateWindowTheme Lib "uxtheme" Alias
"SetWindowTheme" ( _
ByVal hWnd As IntPtr, _
Optional ByRef pszSubAppName As String = " ", _
Optional ByRef pszSubIdList As String = " ") _
As Integer

Private Declare Sub InitCommonControls Lib "comctl32" ()

#Region " Windows Form Designer generated code "

Public Sub New()
MyBase.New()

'This call is required by the Windows Form Designer.
InitializeComponent()

'Add any initialization after the InitializeComponent() call
Call InitCommonControls()
Dim Result As Integer = ActivateWindowTheme(Button1.Handle)
Debug.WriteLine(Result)

End Sub
 
: Private Declare Function ActivateWindowTheme Lib "uxtheme" Alias
: "SetWindowTheme" ( _
: ByVal hWnd As IntPtr, _
: Optional ByVal pszSubAppName As Integer = 0, _
: Optional ByVal pszSubIdList As Integer = 0) _
: As Integer

Untested:

You've omitted pszSubAppName and pszSubIdList, which will disable the theme.
Also, your declare is wrong. Try this:

(Change the integers, to strings)

ActivateWindowTheme(Button1.Handle, "BUTTON", "")

--
HTH,
-- Tom Spink, Über Geek

Please respond to the newsgroup,
so all can benefit

"Maybe it's a game called 'Punish the User'"


: Hi,
:
: I'm develing a COM add-in for Microsoft Word XP that displays a form. I'd
: like to have the form display using the Windows XP theme. However,
neither
: using a manifest nor calling Application.EnableVisualStyles does the
trick.
: (EnableVisualStyles works but massive instability, probably because the
: system is trying to theme the Word application itself.)
:
: I'm now trying to selectively enable the themes for just my form, or just
: certain elements on my form, by using the SetWindowTheme api. My
: understanding is that SetWindowTheme doesn't need a manifest to work.
(MSDN
: isn't particularly clear.)
:
: Herfried posted an article that discussed using this function with VB6:
: http://www.activevb.de/tutorials/tut_xpstyles/xpstyles.html
:
: Here's a (poorly) translated version:
:
http://translate.google.com/translate?sourceid=navclient-menuext&hl=en&u=htt
p%3A%2F%2Fwww%2Eactivevb%2Ede%2Ftutorials%2Ftut%5Fxpstyles%2Fxpstyles%2Ehtml
: (You gotta love using the "Communist manifesto" in Visual Basic. <g>)
:
: I created a test WinForms app that contains just a simple form with a
: button. In the code below, I'm trying to theme the button. The function
is
: returning a 0 (success?) but still appears in the classic style. It
happens
: regardless of whether the button has "Standard" or "System" FlatStyle.
:
: Any suggestions?
:
: Thanks,
: Robert Jacobson
:
:
:
: Private Declare Function ActivateWindowTheme Lib "uxtheme" Alias
: "SetWindowTheme" ( _
: ByVal hWnd As IntPtr, _
: Optional ByVal pszSubAppName As Integer = 0, _
: Optional ByVal pszSubIdList As Integer = 0) _
: As Integer
:
: Private Declare Function DeactivateWindowTheme Lib "uxtheme" Alias
: "SetWindowTheme" ( _
: ByVal hWnd As IntPtr, _
: Optional ByRef pszSubAppName As String = " ", _
: Optional ByRef pszSubIdList As String = " ") _
: As Integer
:
: Private Declare Sub InitCommonControls Lib "comctl32" ()
:
: #Region " Windows Form Designer generated code "
:
: Public Sub New()
: MyBase.New()
:
: 'This call is required by the Windows Form Designer.
: InitializeComponent()
:
: 'Add any initialization after the InitializeComponent() call
: Call InitCommonControls()
: Dim Result As Integer = ActivateWindowTheme(Button1.Handle)
: Debug.WriteLine(Result)
:
: End Sub
:
:
 
Thanks, Tom.

Revised code, with a more traditional declare for SetWindowTheme:

Private Declare Function SetWindowTheme Lib "uxtheme" ( _
ByVal hWnd As IntPtr, _
ByRef pszSubAppName As String, _
ByRef pszSubIdList As String) _
As Integer
....
Dim Result As Integer = SetWindowTheme(Button1.Handle, "BUTTON", "")

Unfortunately, it didn't work -- I'm still getting the classic style.

My first code was just a port of Herfried's code to VB.Net. I think he was
using zeroes for the last two properties as substitutes for a null string.
(Hard for me to know exactly -- the automated translation of the page was
really bad, and my German's even worse. <g>)

Any other thoughts?

--Robert
 
Well Yes, It was silly of me to suggest it, because thinking about it, you
are going to need a manifest, no matter what, because your application needs
to reference Version 6 of common controls.

The reason SetWindowTheme doesn't work is because it's designed for setting
the theme, when Common Controls 6 are being used, and Herfried uses it to
disabled themes.

However, do not despair... I have written a control that owner-draw's a
button all the way, using uxtheme.dll.

http://download.betasafe.com/ActiveButton.zip


--
HTH,
-- Tom Spink, Über Geek

Please respond to the newsgroup,
so all can benefit

"Maybe it's a game called 'Punish the User'"


: Thanks, Tom.
:
: Revised code, with a more traditional declare for SetWindowTheme:
:
: Private Declare Function SetWindowTheme Lib "uxtheme" ( _
: ByVal hWnd As IntPtr, _
: ByRef pszSubAppName As String, _
: ByRef pszSubIdList As String) _
: As Integer
: ...
: Dim Result As Integer = SetWindowTheme(Button1.Handle, "BUTTON", "")
:
: Unfortunately, it didn't work -- I'm still getting the classic style.
:
: My first code was just a port of Herfried's code to VB.Net. I think he
was
: using zeroes for the last two properties as substitutes for a null string.
: (Hard for me to know exactly -- the automated translation of the page was
: really bad, and my German's even worse. <g>)
:
: Any other thoughts?
:
: --Robert
:
:
: : > : Private Declare Function ActivateWindowTheme Lib "uxtheme" Alias
: > : "SetWindowTheme" ( _
: > : ByVal hWnd As IntPtr, _
: > : Optional ByVal pszSubAppName As Integer = 0, _
: > : Optional ByVal pszSubIdList As Integer = 0) _
: > : As Integer
: >
: > Untested:
: >
: > You've omitted pszSubAppName and pszSubIdList, which will disable the
: theme.
: > Also, your declare is wrong. Try this:
: >
: > (Change the integers, to strings)
: >
: > ActivateWindowTheme(Button1.Handle, "BUTTON", "")
: >
: > --
: > HTH,
: > -- Tom Spink, Über Geek
: >
: > Please respond to the newsgroup,
: > so all can benefit
: >
: > "Maybe it's a game called 'Punish the User'"
: >
: >
: > : > : Hi,
: > :
: > : I'm develing a COM add-in for Microsoft Word XP that displays a form.
: I'd
: > : like to have the form display using the Windows XP theme. However,
: > neither
: > : using a manifest nor calling Application.EnableVisualStyles does the
: > trick.
: > : (EnableVisualStyles works but massive instability, probably because
the
: > : system is trying to theme the Word application itself.)
: > :
: > : I'm now trying to selectively enable the themes for just my form, or
: just
: > : certain elements on my form, by using the SetWindowTheme api. My
: > : understanding is that SetWindowTheme doesn't need a manifest to work.
: > (MSDN
: > : isn't particularly clear.)
: > :
: > : Herfried posted an article that discussed using this function with
VB6:
: > : http://www.activevb.de/tutorials/tut_xpstyles/xpstyles.html
: > :
: > : Here's a (poorly) translated version:
: > :
: >
:
http://translate.google.com/translate?sourceid=navclient-menuext&hl=en&u=htt
: >
:
p%3A%2F%2Fwww%2Eactivevb%2Ede%2Ftutorials%2Ftut%5Fxpstyles%2Fxpstyles%2Ehtml
: > : (You gotta love using the "Communist manifesto" in Visual Basic. <g>)
: > :
: > : I created a test WinForms app that contains just a simple form with a
: > : button. In the code below, I'm trying to theme the button. The
: function
: > is
: > : returning a 0 (success?) but still appears in the classic style. It
: > happens
: > : regardless of whether the button has "Standard" or "System" FlatStyle.
: > :
: > : Any suggestions?
: > :
: > : Thanks,
: > : Robert Jacobson
: > :
: > :
: > :
: > : Private Declare Function ActivateWindowTheme Lib "uxtheme" Alias
: > : "SetWindowTheme" ( _
: > : ByVal hWnd As IntPtr, _
: > : Optional ByVal pszSubAppName As Integer = 0, _
: > : Optional ByVal pszSubIdList As Integer = 0) _
: > : As Integer
: > :
: > : Private Declare Function DeactivateWindowTheme Lib "uxtheme" Alias
: > : "SetWindowTheme" ( _
: > : ByVal hWnd As IntPtr, _
: > : Optional ByRef pszSubAppName As String = " ", _
: > : Optional ByRef pszSubIdList As String = " ") _
: > : As Integer
: > :
: > : Private Declare Sub InitCommonControls Lib "comctl32" ()
: > :
: > : #Region " Windows Form Designer generated code "
: > :
: > : Public Sub New()
: > : MyBase.New()
: > :
: > : 'This call is required by the Windows Form Designer.
: > : InitializeComponent()
: > :
: > : 'Add any initialization after the InitializeComponent() call
: > : Call InitCommonControls()
: > : Dim Result As Integer = ActivateWindowTheme(Button1.Handle)
: > : Debug.WriteLine(Result)
: > :
: > : End Sub
: > :
: > :
: >
: >
:
:
 
Robert,
Private Declare Function SetWindowTheme Lib "uxtheme" ( _
ByVal hWnd As IntPtr, _
ByRef pszSubAppName As String, _
ByRef pszSubIdList As String) _
As Integer

FWIW, the strings should be passed ByVal, and the declaration should
include the Unicode modifier keyword.



Mattias
 
Hello,

Robert Jacobson said:
Revised code, with a more traditional declare for SetWindowTheme:

Private Declare Function SetWindowTheme Lib "uxtheme" ( _
ByVal hWnd As IntPtr, _
ByRef pszSubAppName As String, _
ByRef pszSubIdList As String) _
As Integer

I would use this declare (untested):

\\\
Private Declare Unicode Function SetWindowTheme Lib "uxtheme.dll" ( _
ByVal hWnd As IntPtr, _
ByVal pszSubAppName As String, _
ByVal pszSubIdList As String _
) As Int32
///
 
Very impressive work with the buttons! I see your uxtheme declares in the
Themes module, but it looks like you're handling most of the drawing
yourself. (Unfortunately, although the Buttons are great, I also have a
progess bar and status bar to theme. My app would probably look goofy with
a half-themed appearance.)

Bad news about SetWindowTheme though. I've seen several examples of using a
manifest to enable XP themes and then manually disable themes from
individual controls with SetWindowTheme. (Which won't work for me.) I had
thought that calling InitCommonControls would bypass the need for a
manifest, and then let me selectively turn the visual styles on. Do you
know of any other way to reference version 6, without using
Application.EnableVisualStyles or a manifest?

My only other hope is a real kludge -- first call
Application.EnableVisualStyles (to get the Version 6 reference), then call
SetThemeAppProperties to disable visual styles application-wide (so Word
won't crash), and finally use SetWindowTheme to reenable visual styles for
just my form. That will be my next step, unless you have any other
thoughts.

Thanks again!

--Robert
 
Thanks, Mattias. I changed my declaration but it didn't help. I think the
problems are more fundanmental.
 
Thanks, but unfortunately, it doesn't help. It sounds like it won't work
without a manifest or Application.EnableVisualStyles. Please let me know if
I'm wrong.
 
Hello,

Robert Jacobson said:
Thanks, but unfortunately, it doesn't help. It sounds like
it won't work without a manifest or Application.EnableVisualStyles.
Please let me know if I'm wrong.

You will still need an application manifest.
 
I looked at the IL for Application.EnableVisualStyles, and all it does is
enable a shared boolean in the application object....

I have no idea how this enables visual styles.

--
HTH,
-- Tom Spink, Über Geek

Please respond to the newsgroup,
so all can benefit

"Chaos, Panic, Disorder, my work here is done"


: Very impressive work with the buttons! I see your uxtheme declares in the
: Themes module, but it looks like you're handling most of the drawing
: yourself. (Unfortunately, although the Buttons are great, I also have a
: progess bar and status bar to theme. My app would probably look goofy
with
: a half-themed appearance.)
:
: Bad news about SetWindowTheme though. I've seen several examples of using
a
: manifest to enable XP themes and then manually disable themes from
: individual controls with SetWindowTheme. (Which won't work for me.) I
had
: thought that calling InitCommonControls would bypass the need for a
: manifest, and then let me selectively turn the visual styles on. Do you
: know of any other way to reference version 6, without using
: Application.EnableVisualStyles or a manifest?
:
: My only other hope is a real kludge -- first call
: Application.EnableVisualStyles (to get the Version 6 reference), then call
: SetThemeAppProperties to disable visual styles application-wide (so Word
: won't crash), and finally use SetWindowTheme to reenable visual styles for
: just my form. That will be my next step, unless you have any other
: thoughts.
:
: Thanks again!
:
: --Robert
:
:
:
:
:
:
: : > Well Yes, It was silly of me to suggest it, because thinking about it,
you
: > are going to need a manifest, no matter what, because your application
: needs
: > to reference Version 6 of common controls.
: >
: > The reason SetWindowTheme doesn't work is because it's designed for
: setting
: > the theme, when Common Controls 6 are being used, and Herfried uses it
to
: > disabled themes.
: >
: > However, do not despair... I have written a control that owner-draw's a
: > button all the way, using uxtheme.dll.
: >
: > http://download.betasafe.com/ActiveButton.zip
: >
: >
: > --
: > HTH,
: > -- Tom Spink, Über Geek
: >
: > Please respond to the newsgroup,
: > so all can benefit
: >
: > "Maybe it's a game called 'Punish the User'"
: >
: >
: > : > : Thanks, Tom.
: > :
: > : Revised code, with a more traditional declare for SetWindowTheme:
: > :
: > : Private Declare Function SetWindowTheme Lib "uxtheme" ( _
: > : ByVal hWnd As IntPtr, _
: > : ByRef pszSubAppName As String, _
: > : ByRef pszSubIdList As String) _
: > : As Integer
: > : ...
: > : Dim Result As Integer = SetWindowTheme(Button1.Handle, "BUTTON", "")
: > :
: > : Unfortunately, it didn't work -- I'm still getting the classic style.
: > :
: > : My first code was just a port of Herfried's code to VB.Net. I think
he
: > was
: > : using zeroes for the last two properties as substitutes for a null
: string.
: > : (Hard for me to know exactly -- the automated translation of the page
: was
: > : really bad, and my German's even worse. <g>)
: > :
: > : Any other thoughts?
: > :
: > : --Robert
: > :
: > :
: > : : > : > : Private Declare Function ActivateWindowTheme Lib "uxtheme" Alias
: > : > : "SetWindowTheme" ( _
: > : > : ByVal hWnd As IntPtr, _
: > : > : Optional ByVal pszSubAppName As Integer = 0, _
: > : > : Optional ByVal pszSubIdList As Integer = 0) _
: > : > : As Integer
: > : >
: > : > Untested:
: > : >
: > : > You've omitted pszSubAppName and pszSubIdList, which will disable
the
: > : theme.
: > : > Also, your declare is wrong. Try this:
: > : >
: > : > (Change the integers, to strings)
: > : >
: > : > ActivateWindowTheme(Button1.Handle, "BUTTON", "")
: > : >
: > : > --
: > : > HTH,
: > : > -- Tom Spink, Über Geek
: > : >
: > : > Please respond to the newsgroup,
: > : > so all can benefit
: > : >
: > : > "Maybe it's a game called 'Punish the User'"
: > : >
: > : >
: message
: > : > : > : > : Hi,
: > : > :
: > : > : I'm develing a COM add-in for Microsoft Word XP that displays a
: form.
: > : I'd
: > : > : like to have the form display using the Windows XP theme.
However,
: > : > neither
: > : > : using a manifest nor calling Application.EnableVisualStyles does
the
: > : > trick.
: > : > : (EnableVisualStyles works but massive instability, probably
because
: > the
: > : > : system is trying to theme the Word application itself.)
: > : > :
: > : > : I'm now trying to selectively enable the themes for just my form,
or
: > : just
: > : > : certain elements on my form, by using the SetWindowTheme api. My
: > : > : understanding is that SetWindowTheme doesn't need a manifest to
: work.
: > : > (MSDN
: > : > : isn't particularly clear.)
: > : > :
: > : > : Herfried posted an article that discussed using this function with
: > VB6:
: > : > : http://www.activevb.de/tutorials/tut_xpstyles/xpstyles.html
: > : > :
: > : > : Here's a (poorly) translated version:
: > : > :
: > : >
: > :
: >
:
http://translate.google.com/translate?sourceid=navclient-menuext&hl=en&u=htt
: > : >
: > :
: >
:
p%3A%2F%2Fwww%2Eactivevb%2Ede%2Ftutorials%2Ftut%5Fxpstyles%2Fxpstyles%2Ehtml
: > : > : (You gotta love using the "Communist manifesto" in Visual Basic.
: <g>)
: > : > :
: > : > : I created a test WinForms app that contains just a simple form
with
: a
: > : > : button. In the code below, I'm trying to theme the button. The
: > : function
: > : > is
: > : > : returning a 0 (success?) but still appears in the classic style.
It
: > : > happens
: > : > : regardless of whether the button has "Standard" or "System"
: FlatStyle.
: > : > :
: > : > : Any suggestions?
: > : > :
: > : > : Thanks,
: > : > : Robert Jacobson
: > : > :
: > : > :
: > : > :
: > : > : Private Declare Function ActivateWindowTheme Lib "uxtheme" Alias
: > : > : "SetWindowTheme" ( _
: > : > : ByVal hWnd As IntPtr, _
: > : > : Optional ByVal pszSubAppName As Integer = 0, _
: > : > : Optional ByVal pszSubIdList As Integer = 0) _
: > : > : As Integer
: > : > :
: > : > : Private Declare Function DeactivateWindowTheme Lib "uxtheme"
Alias
: > : > : "SetWindowTheme" ( _
: > : > : ByVal hWnd As IntPtr, _
: > : > : Optional ByRef pszSubAppName As String = " ", _
: > : > : Optional ByRef pszSubIdList As String = " ") _
: > : > : As Integer
: > : > :
: > : > : Private Declare Sub InitCommonControls Lib "comctl32" ()
: > : > :
: > : > : #Region " Windows Form Designer generated code "
: > : > :
: > : > : Public Sub New()
: > : > : MyBase.New()
: > : > :
: > : > : 'This call is required by the Windows Form Designer.
: > : > : InitializeComponent()
: > : > :
: > : > : 'Add any initialization after the InitializeComponent() call
: > : > : Call InitCommonControls()
: > : > : Dim Result As Integer = ActivateWindowTheme(Button1.Handle)
: > : > : Debug.WriteLine(Result)
: > : > :
: > : > : End Sub
: > : > :
: > : > :
: > : >
: > : >
: > :
: > :
: >
: >
:
:
 
Back
Top