this function will fix properly following issues with Visual Styles (Themes):
- Frame control (black background on controls)
- Focus rectangles not shown
- Accelerator keys not shown
- CommandButton, CheckBox and OptionButton with Graphical Style not themed
In order to use this function you first need to create a manifest:
Is there any reason why the Frame, TextBox, ComboBox and ListBox have their Visual Styles removed? I tried running them with their Visual Styles applied, and they worked OK for me.
Last edited by Bonnie West; May 17th, 2013 at 03:27 AM.
On Local Error Resume Next: If Not Empty Is Nothing Then Do While Null: ReDim i(True To False) As Currency: Loop: Else Debug.Assert CCur(CLng(CInt(CBool(False Imp True Xor False Eqv True)))): Stop: On Local Error GoTo 0
Last edited by Bonnie West; May 17th, 2013 at 03:18 AM.
Reason: Added bugfixes reminder
On Local Error Resume Next: If Not Empty Is Nothing Then Do While Null: ReDim i(True To False) As Currency: Loop: Else Debug.Assert CCur(CLng(CInt(CBool(False Imp True Xor False Eqv True)))): Stop: On Local Error GoTo 0
On my system (XP), the same quirk is also present on unsubclassed CommandButtons, especially evident when the BackColor contrasts sharply with the current theme color of the button. I guess it's a cosmetic bug on VB's side.
On Local Error Resume Next: If Not Empty Is Nothing Then Do While Null: ReDim i(True To False) As Currency: Loop: Else Debug.Assert CCur(CLng(CInt(CBool(False Imp True Xor False Eqv True)))): Stop: On Local Error GoTo 0
I do not get that. With no manifest a command button with Graphical Style and BackColor = vbred gives me a button with a red face, on Win2k, XP and W7.
With a manifest I still get a button with a red face but it has sharp corners rather than the nice curved ones applied to non-graphical buttons. Using the code above I loose the colored face.
You need to use the same BackColor for the graphical button as the container. (normally vbButtonFace)
The graphical button will be drawn with the system theme BackColor.
As a work-around, you may want to modify the SetupVisualStyles subroutine in order to exclude particular graphical buttons.
On Local Error Resume Next: If Not Empty Is Nothing Then Do While Null: ReDim i(True To False) As Currency: Loop: Else Debug.Assert CCur(CLng(CInt(CBool(False Imp True Xor False Eqv True)))): Stop: On Local Error GoTo 0
FALSE and TRUE are both appended with Chr(160) aka (non-breaking space), ALT-0160 on the numeric keypad. By doing it that way, VB won't see them as a reserved keyword.
On Local Error Resume Next: If Not Empty Is Nothing Then Do While Null: ReDim i(True To False) As Currency: Loop: Else Debug.Assert CCur(CLng(CInt(CBool(False Imp True Xor False Eqv True)))): Stop: On Local Error GoTo 0
Great code! But there's one more fix I desperately need for my ageing VB6 app: when applying visual styles, textboxes no longer seem to apply the Font.Charset property. This is a major blow to me as the various edit boxes in the app need to display text based on the user's chosen character set.
A quick aside: Oddly enough, unlike in the VB6 IDE/VB app without manifests, the text box *will* display just about any character from any codepage that you paste into it from Character Map. Suddenly it seems to be 100% Unicode (something we all wanted so much all those years ago!).
While you can paste Unicode symbols in and they display that way you can't do anything with them, even via Unicode API calls. That's because the underlying control is still a VB6 ThunderTextBox/ThunderRT6TextBox, which are ANSI controls.
If you really want to do this you might try the InkEdit control. This is included in Vista and later, or XP Tablet Edition, and there is a redist that can be used for plain old XP. The control can be used "inklessly" and seems to be fully Unicode enabled, and they're actually Unicode RTBs with ink entry capability.
Thanks for the reply, dilettante. Actually, I'm not worried about the lack of Unicode support. As you rightly point out, the textboxes are still plain old VB6 textboxes. What I'd like to know is why, when themed, they no longer respond to changes to their Font.Charset. Listboxes, listviews, etc. still do, but textboxes don't. Is there a workaround for this?
I think it is because inside of the VB6 TextBox is a standard ANSI Edit control. The version in Common Controls 6.0 can accept pasted Unicode but apparently hasn't implemented CharSet as you point out.
I'm not sure what testing might show if you tried using the WM_SETFONT message to alter the Charset. VB6's StdFont objects don't expose (even a hidden) Font handle, so you'd have to resort to the CreateFont() API first.
Using WM_SETFONT with CreateFont() didn't help, I'm afraid. Same result. But thanks for the suggestion.
To come so far and be stopped by what should be such a trivial issue is hugely frustrating.
What I need (in order to be able to add visual styles to my app) is a simple non-Unicode edit control that responds to a Font.Charset change when themed. Neither the standard VB6 textbox/richtextbox nor a user control based on RichEdit20A allows this. I've tried sending all three 1) an EM_SETTEXTMODE message with TM_PLAINTEXT | TM_SINGLECODEPAGE; 2) an EM_SETCHARFORMAT message with dwMask = CFM_CHARSET and CHARFORMAT.bCharSet set to the desired character set; and 3) setting the font using CreateFontIndirect. Nothing works.
As I mentioned in my OP, the theme bug (for want of a better word) is very easy to reproduce:
1. Add a text box to a VB6 project and set its text to "á" (lowercase "a" with acute).
2. Add a button which changes the charset of the text box to e.g. Greek (just an example; any charset can be used): Text1.Font.Charset = 161.
Now:
3. Run the app in a non-themed environment and click the button. The "á" in the textbox changes to Greek lowercase alpha ("α"). This is the standard behaviour of my app when running without visual styles and it's the behaviour the whole app is based on and requires.
And now:
4. Run the app in a themed environment and click the button. The "á" in the textbox does not change, no matter how you tell the edit box to change the charset.
I've searched high and low for mention of this behaviour and the only thing I've found is one small line at http://www.cyberactivex.com/UnicodeTutorialVb.htm - "Warning: If you apply an XP Theme to the TextBox below via an IDE Manifest it will display ANSI instead of DBCS." To which I'd add "And changing the TextBox's Font.Charset property will have no effect, either".
How about forgoing Visual Styles on that particular TextBox? After all, themed and unthemed TextBoxes don't look noticeably different from each other. The SetWindowTheme API might help in this case.
Code:
Private Declare Function SetWindowTheme Lib "uxtheme.dll" (ByVal hWnd As Long, ByVal pszSubAppName As Long, ByVal pszSubIdList As Long) As Long
Private Sub Form_Load()
SetWindowTheme Text1.hWnd, StrPtr(" "), StrPtr(" ")
End Sub
' Or
Private Declare Function RemoveTheme Lib "uxtheme.dll" Alias "SetWindowTheme" (ByVal hWnd As Long, Optional ByVal pszSubAppName As String = " ", Optional ByVal pszSubIdList As String = " ") As Long
Private Sub Form_Load()
RemoveTheme Text1.hWnd
End Sub
On Local Error Resume Next: If Not Empty Is Nothing Then Do While Null: ReDim i(True To False) As Currency: Loop: Else Debug.Assert CCur(CLng(CInt(CBool(False Imp True Xor False Eqv True)))): Stop: On Local Error GoTo 0
Thanks for the idea, Bonnie. I'd actually already tried this and guess what? It makes no difference.
Creating a textbox with CreateWindowEx after the app has loaded, removing its theme and changing its charset with WM_SETFONT doesn't work, either.
What I need (in order to be able to add visual styles to my app) is a simple non-Unicode edit control that responds to a Font.Charset change when themed.
Well you probably just aren't going to get that.
Can we back up a little? Why are you doing this and what do you want to get out of it? Perhaps there is another way to accomplish what you're after instead of getting there by exploiting a quirk in the older control.
I'd try approaching things that way and creating a question thread in a more appropriate part of the site (like the VB6 Q&A forum) instead of here in the CodeBank. Kind of stated something like "Here is what I am doing and what is now failing. Is there another way to accomplish this?"
Last edited by dilettante; Sep 24th, 2012 at 11:15 AM.
Reason: Silly typo. If only the site would stay up long enough to get your posts right!
Apologies if this was the wrong place to post to. The VB6 application I'd like to add visual styles to is a subtitle editor (http://www.spotsoftware.nl/spot.shtml). This means it has to be able to display text in multiple character sets (Western, Central European, Hebrew, Cyrillic, Turkish, Chinese Traditional, etc.). It does this by switching the character set of its main text editing area (just a simple VB multiline textbox) whenever necessary. So that's what I'm doing. It's worked fine for the last 15 years (yes, it's an old app that's been in development a long time!), but breaks when visual styles are added for the reason mentioned above (I can no longer change character sets) and so that's what's failing. Thanks to everyone for their suggestions.
CodeBank threads are primarily archival. You really only want to post comments or questions about the code being offered there. For example bugs, how to use the code, whether a new version exists, and so on.
For general questions the Q&A forum is better. If the question is related to a CodeBank thread you can always add a link to the CodeBank thread in your question thread.
Request
Kroll, Can you add to your function SetupVisualStyles, support Unicode for form's title(caption)?
I write in each form's this code, from this thread, and it Works
Code:
Private Const WM_GETTEXT = &HD
Private Const WM_GETTEXTLENGTH = &HE
Private Const WM_SETTEXT = &HC
Private Declare Function DefWindowProc Lib "user32.dll" Alias "DefWindowProcW" (ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Public Property Let CaptionW(ByVal NewValue As String)
DefWindowProc Me.hWnd, WM_SETTEXT, 0, ByVal StrPtr(NewValue & vbNullChar)
End Property
Public Property Get CaptionW() As String
Dim strLen As Long
strLen = DefWindowProc(Me.hWnd, WM_GETTEXTLENGTH, 0, ByVal 0)
CaptionW = Space$(strLen)
DefWindowProc Me.hWnd, WM_GETTEXT, Len(CaptionW) + 1, ByVal StrPtr(CaptionW & vbNullChar)
End Property
Last edited by Romeo91; Feb 10th, 2014 at 10:10 PM.
What is the point of VBCCR/ActiveX Control Version/Common/VisualStyles.bas ?
Are these style-related fixes only a problem for the Standard EXE Version?
If I don't want myself or my users to experience visual style issues, and I use the ActiveX Control Version, do I not need to InitVisualStylesFixes or do any of the things you described in the first post?
Last edited by OldClock; Jul 30th, 2020 at 11:31 AM.
What is the point of VBCCR/ActiveX Control Version/Common/VisualStyles.bas ?
Are these style-related fixes only a problem for the Standard EXE Version?
If I don't want myself or my users to experience visual style issues, and I use the ActiveX Control Version, do I not need to InitVisualStylesFixes or do any of the things you described in the first post?
This is the endless discussion between OCX and Std-EXE.
A OCX (regardless which OCX) is not obliged to fix any visual styles issues. It can have only a stripped down set of function to know if comctl32.dll 5.8x is applicable (not manifested) or 6.x (manifested).
The Std-EXE needs to fix any visual styles issues and also always needs to manifest. The OCX is just attached to the Std-EXE later on and runs in the same process.
Thanks, but due to the language barrier (not sure what you mean by "not obliged") and due to my unfamiliarity with OCX I'm still not clear on the situation.
1. The Std-EXE version is susceptible to some visual style bugs. Do these visual style bugs also affect programs using the OCX version?
2. Does using InitVisualStylesFixes/SetupVisualStylesFixes(Me) fix anything when using the OCX version, or should I remove that if it does nothing?
Thanks, but due to the language barrier (not sure what you mean by "not obliged") and due to my unfamiliarity with OCX I'm still not clear on the situation.
1. The Std-EXE version is susceptible to some visual style bugs. Do these visual style bugs also affect programs using the OCX version?
2. Does using InitVisualStylesFixes/SetupVisualStylesFixes(Me) fix anything when using the OCX version, or should I remove that if it does nothing?
1. Yes.
2. Yes, use the fixes in a Std-exe project that is linked to the OCX.