Option Explicit
Private Const ICC_STANDARD_CLASSES As Long = &H4000&
Private Type tagINITCOMMONCONTROLSEX
dwSize As Long
dwICC As Long
End Type
Private Declare Function InitShell Lib "shell32" Alias "IsUserAnAdmin" () As Long
Private Declare Function InitCommonControls Lib "comctl32.dll" () As Long
Private Declare Function InitCommonControlsEx Lib "comctl32.dll" (iccex As Any) As Boolean
Public Sub InitComCtls()
On Error Resume Next
Dim lgRet As Long
Dim ICC As tagINITCOMMONCONTROLSEX
With ICC
.dwSize = Len(ICC)
.dwICC = ICC_STANDARD_CLASSES
End With
Call InitShell
lgRet = InitCommonControlsEx(ICC)
If lgRet = 0 Or Err.Number <> 0 Then
Call InitCommonControls ' 9x version
End If
Exit Sub
End Sub
Call procedure:
Code:
Private Sub Form_Initialize()
On Error Resume Next
Call InitComCtls
Exit Sub
End Sub
The thing is that, how I see, the code above does not have any effect/function, it's working without the code is called.
Any thoughts about it?
But my real questions are:
After implementing the Manifest styling, I can't change the forecolor of any object, I'm talking here especially about Frame forecolor (can't change from blue to black, shown on image bellow).
And a second thing is that, my Command buttons located in a Frame got black framed arround, but I don't know why.
These weird things are only shown on Windows XP, but on Windows 7 and Windows 10 are showing up just great.
my Command buttons located in a Frame got black framed arround, but I don't know why.
These weird things are only shown on Windows XP, but on Windows 7 and Windows 10 are showing up just great.
Thank you!
In Windows XP, this happens if you put Command buttons, checkboxes, radiobuttons, ect. in a Frame Control directly. As a workaround, in the frame control, you just put a PictureBox and put command buttons inside the PictureBox and set PictureBox's BorderStyle to None and set its BackColor to the BackColor of the Frame.
Last edited by PGBSoft; Oct 7th, 2018 at 12:52 PM.
This happens if you put Command buttons, checkboxes, radiobuttons, ect. in a Frame Control directly. As a workaround, in the frame control, you just put command buttons inside a picturebox and set PictureBox's BorderStyle to None and set BackColor to the BackColor of the Frame.
Thank you for your fast response and for the workaround suggestion.
But, is there any advanced solution like API calls or something like that?
The reason to call IsUserAnAdmin and InitCommonControls before any VB6 Forms or controls load is to ensure that the proper versions of the two libraries containing these entrypoints get loaded into the process before the VB6 runtime can screw things up.
You could just as easily do a LoadLibrary on both shell32 and comctl32 instead, but by rights you should hang onto the handles returned and call FreeLibrary on them before your program exits.
Both calls are no-ops as far as our programs are concerned. They are just easy tricks to cause the two libraries to be loaded and freed without a lot of fiddling.
People who call InitCommonControlsEx are just cargo-culting. There is nothing to be gained here if you are using normal VB6 intrinsic controls and OCX controls, since they'll take care of any InitCommonControlsEx calls required by themselves. Sure, you can do it instead of calling InitCommonControls by why jump through the extra hoops? Doing both is just silly.
Either way you go, these calls are best done in a Sub Main and not deferred until a Form_Initialize event even though you might get away with that most of the time... Right up until it doesn't and then you have a lot of head-scratching to do. Just do it right, do it first thing in Sub Main.
The UxTheme varies from version to version of Windows but in many places it does take priority over the old-style color attributes of controls. This is intentional. The whole idea of the theming is to give applications a consistent look.
As far as your "black frame around buttons in a Frame" goes, it is probably an artifact of rendering Win32-based controls like a Command button within the Frame, which is a lightweight ActiveX container control. OLE2 and Win32 GDI sort of "battle it out" over rendering in that scenario. It might look better on a later OS where the Win32 control has changed a bit, but probably not due to any concessions made for the VB6 Frame. It is probably more luck than anything else.
The reason to call IsUserAnAdmin and InitCommonControls before any VB6 Forms or controls load is to ensure that the proper versions of the two libraries containing these entrypoints get loaded into the process before the VB6 runtime can screw things up.
You could just as easily do a LoadLibrary on both shell32 and comctl32 instead, but by rights you should hang onto the handles returned and call FreeLibrary on them before your program exits.
Both calls are no-ops as far as our programs are concerned. They are just easy tricks to cause the two libraries to be loaded and freed without a lot of fiddling.
People who call InitCommonControlsEx are just cargo-culting. There is nothing to be gained here if you are using normal VB6 intrinsic controls and OCX controls, since they'll take care of any InitCommonControlsEx calls required by themselves. Sure, you can do it instead of calling InitCommonControls by why jump through the extra hoops? Doing both is just silly.
Either way you go, these calls are best done in a Sub Main and not deferred until a Form_Initialize event even though you might get away with that most of the time... Right up until it doesn't and then you have a lot of head-scratching to do. Just do it right, do it first thing in Sub Main.
Okay dilettante,
Do you maybe have some working example by your side regarding LoadLibrary, shell32, comctl32 and FreeLibrary (copy n' paste)?
Originally Posted by dilettante
The UxTheme varies from version to version of Windows but in many places it does take priority over the old-style color attributes of controls. This is intentional. The whole idea of the theming is to give applications a consistent look.
Any suggestion how can I change the already themed controls color property then?
Originally Posted by dilettante
As far as your "black frame around buttons in a Frame" goes, it is probably an artifact of rendering Win32-based controls like a Command button within the Frame, which is a lightweight ActiveX container control. OLE2 and Win32 GDI sort of "battle it out" over rendering in that scenario. It might look better on a later OS where the Win32 control has changed a bit, but probably not due to any concessions made for the VB6 Frame. It is probably more luck than anything else.
I could use the picturebox workaround, but is there any better solution for that?
And as I mentioned before on other Windows like 7 and 10 it's showing perfectly.
If you call IsUserAnAdmin and then InitCommonControls ignoring the returned result you get the libraries loaded just fine, and they'll be freed by the VB6 runtime when your program completes.
I don't bother playing reindeer games with LoadLibrary and FreeLibrary because they offer no advantages over just making the two calls above. If you want to then go right ahead, but I don't have any snippets handy to post here. There just isn't much to it except that you have no reliable point you can call FreeLibrary from.
The VB6 Frame is a windowless control. As such it doesn't not expose an hWnd property which makes it hard to simply call SetWindowTheme to override the theming it gets.
No, I have no idea what you can do about changing how controls are rendered within a Frame control. Since the PictureBox is one of the few non-top-level container types we have people use that a lot. The only other alternative that comes to mind is to use UserControls.
Code:
Option Explicit
Private Enum HRESULT
S_OK = 0
End Enum
Private Declare Function SetWindowTheme Lib "UxTheme" ( _
ByVal hWnd As Long, _
ByVal pszSubAppName As Long, _
ByVal pszSubIdList As Long) As HRESULT
Private Sub Form_Initialize()
SetWindowTheme Command1.hWnd, StrPtr(" "), StrPtr(" ")
SetWindowTheme Command3.hWnd, StrPtr(" "), StrPtr(" ")
End Sub
This code overrides theming on two of the Command buttons.
We can't do that on a Frame, but we could use our own "UCFrame" container instead which has no default theming of its own. It can be tricky to get its Shape1's border color correct though, which should be done at runtime by fetching it via additional UxTheme.dll calls such as GetThemeSysColor. The colors change with each OS version.
I have no idea what this looks like on Windows XP.
All of this seems like a lot of work just to have a skinned UI. Why not just avoid fighting Windows and stick with the conventions enforced by the UxTheme system?
Yes, thank you for that!
I did not missed it, I already saw that one, but for me, it's just to complicated and a lot of code are involved.
I like the simpler solution provided by dilettante's UCFrame example in this case.
Originally Posted by dilettante
We can't do that on a Frame, but we could use our own "UCFrame" container instead which has no default theming of its own. It can be tricky to get its Shape1's border color correct though, which should be done at runtime by fetching it via additional UxTheme.dll calls such as GetThemeSysColor. The colors change with each OS version.
I like your UCFrame a lot, but I'm missing the Font properties from it, it's just working fine on Windows XP!
UCFrame is as simple as any custom "skin" which is not aware of themeing.
Basically it will always look the same on each OS, no matter what version, themeing enabled or not.
(dillettante did mention this)
You could easily improve UCFrame by using DrawThemeBackground or DrawFrameControl (when themeing is not available).
That way at least it will match the OS, and it won't be as complicated as Krool's all in one fixups, that hack the original VB controls.
Yeah, it all depends on your needs and how much baggage you are willing to tweak until viable and try to maintain over time.
A simple-minded "UCFrame" control could be enhanced to have a Font and Caption property, maybe a few more such as an Enabled property... and it might be good enough for many applications. If DrawFrameControl and a few more calls can clean it up further (making it adapt to the OS) those may be worthwhile additions.
Or you can go a lot further, even to the point of doing up a whole API-based control.
It is up to you to judge.
But it seems like a long way to go just to be able to set the color that the caption text gets rendered with.
Imagine you make it blue, then a user has one of the low-vision accessibilty themes selected where ButtonFace is black. Now your caption becomes hard to read until it is a light shade of blue. If ButtonFace becomes blue then it may become invisible.
You can get to a point very quickly where a skinned look becomes impractical.
Btw, Krool's code is complicated by Style=Graphical support for various built-in controls.
If you don't need buttons w/ pictures or have another solution for these (e.g. BS_ICON support in recent OS versions) the "hack" is 50-60 lines in total.
Basicly you need to subclass WM_PRINTCLIENT msg on the frames and don't let VB draw the black backgrounds on buttons etc. child controls and in the meantime prevent WM_MOUSELEAVE reaching original wndproc too, just to reduce the annoying flicker on mouse movement (the frame control redrawing windowless child controls like labels etc.)
Yeah I was confused by the Frame not having an hWnd comment too. It has an hWnd and is a full fledged window; I routinely use all sorts of APIs on it, set it as a parent, even subclass it. So the SetWindowTheme call should work like any other windowed control then no? IIRC frames drawn with the theme API like Krools are in fact windowless though.