[RESOLVED] Enabling ComCtl 6 in VB6 IDE with the manifest file no longer works in Windows 10?
I have been using the vb6.exe.manifest file for years since the days of Windows XP to enable visual styles and other cool ComCtl v6 features like 32-bit images with transparency in image lists in VB6 IDE. But it seems, this thing no longer works in Windows 10. At least, here is the picture I see when I upload 32-bit images with transparency into vbAccelerator ImageList control in my Windows 10:
This approach definitely worked in the previous versions of the OS like Windows 7. Have I missed something when I switched to Windows 10?
Re: Enabling ComCtl 6 in VB6 IDE with the manifest file no longer works in Windows 10
Do you use an external manifest file?
I believe dilettante posted somewhere that for manifest files to work on W10 they need to be embedded in the application.
Re: Enabling ComCtl 6 in VB6 IDE with the manifest file no longer works in Windows 10
Oh, yes, I needed to mention this explicitly - I am using an external manifest file. Can anybody point me in the right direction - how to embed this manifest into VB6.exe an easy and correct way?
Re: Enabling ComCtl 6 in VB6 IDE with the manifest file no longer works in Windows 10
On my W7 machine I had a modified VB6.EXE, but on W10 I just use the original version.
Don't care how it looks in the IDE and when my own applications are compiled I do embed a manifest in the EXE.
Re: [RESOLVED] Enabling ComCtl 6 in VB6 IDE with the manifest file no longer works in
External manifest can still be used, though they have been strongly discouraged for over a decade. Embedded manifests take priority over them unless a registry hack is done to reverse the change in policy since the XP days.
Most likely they are working for you, but you have run into the caching that Windows does. If you compile and run a program without a manifest, subsequently plopping one alongside the EXE will not take effect immediately.
If you want to embed manifests in VB6 it is a fairly trivial process.
Create the manifest file as either an ANSI text file that carefully avoid any non-ASCII characters OR an actual BOM-less UTF-8 file. It is worth the effort to pad the file with spaces to an exact multiple of 4 bytes, just in case you run into DWORD padding woes when you embed it.
Then add this file as a Custom resource using the IDE Resource Editor add-in. Rename it as Type #24 and ID #1 and then save the .res file.
An yes, it seems external manifests still work - even for compiled VB6 executables.
Originally Posted by dilettante
Most likely they are working for you, but you have run into the caching that Windows does. If you compile and run a program without a manifest, subsequently plopping one alongside the EXE will not take effect immediately.
Do you know how to clear this cache to force Windows to use the external manifest file if it is provided?
And if you can answer, one more related question. As I understand, the 2010 and 2016 versions of MS Access are linked to ComCtl32 v6 using the custom resource with ID 3:
However, the behavior of vbAccelerator ImageList differs in these versions. We can't use images with transparency in Access 2010, though in Access 2016 all works as expected (the property page of the ImageList OCX is also rendered correctly with visual styles in Access 2016 too). Do you know a way how to force Access 2010 to use ComCtl32 v6 in ActiveX's?
Last edited by wisekat; Jun 9th, 2017 at 04:04 AM.
Re: [RESOLVED] Enabling ComCtl 6 in VB6 IDE with the manifest file no longer works in
Originally Posted by dilettante
If you want to embed manifests in VB6 it is a fairly trivial process.
Create the manifest file as either an ANSI text file that carefully avoid any non-ASCII characters OR an actual BOM-less UTF-8 file. It is worth the effort to pad the file with spaces to an exact multiple of 4 bytes, just in case you run into DWORD padding woes when you embed it.
Oh, one more question regarding this. Don't we need to also call InitCommonControlsEx in addition to this, as it is stated in the article at vbAccelerator.com I referred in my very first post?
Re: [RESOLVED] Enabling ComCtl 6 in VB6 IDE with the manifest file no longer works in
Originally Posted by wisekat
Oh, one more question regarding this. Don't we need to also call InitCommonControlsEx in addition to this, as it is stated in the article at vbAccelerator.com I referred in my very first post?
Yes, you need to
1) start your app using Sub Main
2) load shell32 prior to comctl32 (I use dil's method of calling IsUserAnAdmin to force the runtime to manage loading it)
3) call InitCommonControlsEx or InitCommonControls
Code:
Private Declare Function InitShell Lib "shell32" Alias "IsUserAnAdmin" () As Long
Private Declare Sub InitCommonControls Lib "comctl32" ()
Public Sub Main()
InitShell
InitCommonControls
Form1.Show
End Sub
Last edited by DEXWERX; Jun 9th, 2017 at 06:40 AM.
Re: [RESOLVED] Enabling ComCtl 6 in VB6 IDE with the manifest file no longer works in
1) start your app using Sub Main
or place it inside Form_Initialize().
Also, use Ex-version, otherwise your program will crash on XP in certain circumstances.
Code:
Private Type tagINITCOMMONCONTROLSEX
dwSize As Long
dwICC As Long
End Type
Private Declare Function InitShell Lib "shell32" Alias "IsUserAnAdmin" () As Long
Private Declare Sub InitCommonControls Lib "comctl32" ()
Private Declare Function InitCommonControlsEx Lib "comctl32.dll" (iccex As Any) As Boolean
Private Const ICC_STANDARD_CLASSES As Long = &H4000&
Private Sub Form_Initialize()
On Error Resume Next
Dim ICC As tagINITCOMMONCONTROLSEX
With ICC
.dwSize = Len(ICC)
.dwICC = ICC_STANDARD_CLASSES
End With
InitShell
lr = InitCommonControlsEx(ICC)
If lr = 0 Or Err.Number <> 0 Then
InitCommonControls ' 9x version
End If
end sub
Re: [RESOLVED] Enabling ComCtl 6 in VB6 IDE with the manifest file no longer works in
I've looked into my code I have been using for years since the days of WinXP:
Code:
Private Sub Form_Initialize()
' Initialize Common Control in order to turn on
' Windows XP visual styles (if possible).
' Use only this approach in VB6 as other approaches may crash your
' compiled app which uses UserControls when you terminate the app!
m_hMod = LoadLibrary("shell32.dll")
InitCommonControls
End Sub
Private Sub Form_Unload(Cancel As Integer)
' unload shell32.dll - used only to turn on using visual styles
FreeLibrary m_hMod
End Sub
I do not use the *Ex version of InitCommonControls. Is it bad?
Last edited by wisekat; Jun 9th, 2017 at 10:20 AM.
Reason: Placed actual version of my code
Re: [RESOLVED] Enabling ComCtl 6 in VB6 IDE with the manifest file no longer works in
InitCommonControls() literally does nothing. It is a no-op and has been for a very long time. Calling it via VB's Declare Function causes the DLL to be loaded, something you want to have occur before anything in the runtime or an OCX tries to.
InitCommonControlsEx() does do something, but unless you are creating controls yourself by pure API calls you don't need it. The VB runtime and any OCXs for use with VB already do that themselves as required.
It is just a matter of getting the correct DLL assemblies loaded into your process.
Re: [RESOLVED] Enabling ComCtl 6 in VB6 IDE with the manifest file no longer works in
The manifest cache is cleared every reboot, and as space fills up over time during a Windows run.
Something that changed in Windows 10 was an enhancement that makes shutdown/startup use a hibernate process in most cases. So restarting a hibernated Windows 10 might possibly leave stuff cached.
Re: [RESOLVED] Enabling ComCtl 6 in VB6 IDE with the manifest file no longer works in
The purpose is to force loading the correct assembly. You could also just make use of an explicit LoadLibrary call.
If your code ends up linking to a DLL that loaded the older assembly your process will use that old assembly. The idea is for you to get linked to the newer CC6 DLLs before linking to any other UI DLLs.
Re: [RESOLVED] Enabling ComCtl 6 in VB6 IDE with the manifest file no longer works in
Originally Posted by dilettante
The purpose is to force loading the correct assembly. You could also just make use of an explicit LoadLibrary call.
If your code ends up linking to a DLL that loaded the older assembly your process will use that old assembly. The idea is for you to get linked to the newer CC6 DLLs before linking to any other UI DLLs.
right, so i'm figuring if you trigger the loading if shell32 first, that's all that needs to happen? (I don't actually know I haven't tested this)
The controls each call InitCommonControlsEx before loading.
Re: [RESOLVED] Enabling ComCtl 6 in VB6 IDE with the manifest file no longer works in
I definitely had a problem with crash on XP with some versions of my programs due to the InitCommonControls preference.
For some unknown reasons I cannot reproduce it now.
Re: [RESOLVED] Enabling ComCtl 6 in VB6 IDE with the manifest file no longer works in
As far as I can determine you need to cause shell32.dll to load first, then comctl32.dll, and then you are ok on any version of Windows (er, from XP to present).
There have always been cases where skipping one or both DLL loads would work... until suddenly the same program just crashes. it probably has to do with what has already been loaded by other processes in the system. DLLs are shared unless isolated through one technique or another.
It has some additional background that may help explain why those DLLs need to get loaded early, for example:
Also note, that historically some controls used to be implemented in USER32.DLL (window classes like, for example, BUTTON or EDIT), while others (known as common controls) resided in COMCTL32.DLL. This has changed with the introduction of COMCTL32.DLL version 6, and now all theming-aware controls live there.
Gotcha: The old (unthemed) implementation of standard controls is still available in USER32.DLL. If you instruct the linker to link your application with COMCTL32.DLL, it may silently omit it if the application never calls any function from it. Hence I recommend you to call InitCommonControls() when initializing the application. Otherwise, the app may be just unthemed instead of not working, using the old controls, masking perfectly the root cause of the problem.
It has some additional background that may help explain why those DLLs need to get loaded early, for example:
Interesting, Thanks for the info. Basically if any control is loaded that doesn't call InitCommonControls/Ex the app may end up using an older (unthemed) control.
Knowing the history - It's much better being safe than sorry.
Re: [RESOLVED] Enabling ComCtl 6 in VB6 IDE with the manifest file no longer works in
Basically if any control is loaded that doesn't call InitCommonControls/Ex the app may end up using an older (unthemed) control.
You can also manage "themed" of each control
Code:
Private Declare Function SetWindowTheme Lib "UxTheme.dll" (ByVal hWnd As Long, ByVal pszSubAppName As Long, ByVal pszSubIdList As Long) As Long
...
' OFF
SetWindowTheme Command1.hWnd, StrPtr(" "), StrPtr(" ")
...
' ON
SetWindowTheme Command1.hWnd, StrPtr("Explorer"), 0&
E.g., usefull in XP, where some controls is visually bugged (on frames e.t.c.).
Re: [RESOLVED] Enabling ComCtl 6 in VB6 IDE with the manifest file no longer works in
Originally Posted by dilettante
If you want to embed manifests in VB6 it is a fairly trivial process.
Create the manifest file as either an ANSI text file that carefully avoid any non-ASCII characters OR an actual BOM-less UTF-8 file. It is worth the effort to pad the file with spaces to an exact multiple of 4 bytes, just in case you run into DWORD padding woes when you embed it.
Then add this file as a Custom resource using the IDE Resource Editor add-in. Rename it as Type #24 and ID #1 and then save the .res file.
I tried to do this for the sake of interest - to see whether I can complete this task using only VB IDE. And know what? I could not specify the type 24 AS NUMBER for the custom resource with the manifest. Can you tell me the secret how to do that? I always get a string "24" but not 24 as a number if I use the Properties dialog for that:
To compare. Here are the same resource editor windows for the resource file that specifies the manifest as a resource correctly (what I created using rc.exe):
As you can see, the Type field is even absent!
P.S. Sorry for these big screens from an UltraHD monitor
Last edited by wisekat; Jun 15th, 2017 at 04:00 AM.
Re: [RESOLVED] Enabling ComCtl 6 in VB6 IDE with the manifest file no longer works in
It is sort of like the confusion produced by implicit type coercion in source code expressions.
For a Custom resource the Type and Id are always String values. But because every so often you need them to be "Int Resource" format as produced by the MAKEINTRESOURCE macro, the VB Resource Editor add-in accepts a "#" prefix to tell it what to do with the numeric String following it.
In a way it is like the difference between "1/1/1990" and #1/1/1990# in VB source code.
Re: [RESOLVED] Enabling ComCtl 6 in VB6 IDE with the manifest file no longer works in
When you see 24 (not "24") then more than likely the resource file was created with a tool like my Manifest Creator, RC.exe, etc. As mentioned in previous two posts, if adding it with the VB resource editor, then prefix with the # sign.
Insomnia is just a byproduct of, "It can't be done"
Re: [RESOLVED] Enabling ComCtl 6 in VB6 IDE with the manifest file no longer works in
The 24 is a MANIFEST resource type, and the VB6 add-in doesn't support adding them. The trick is to use a CUSTOM resource with ID #24, and when it saves as .RES it retains that... but by the time the EXE is created these become MANIFEST (24) type resources.
You can use ResHacker, etc. to open your compiled EXE and see that.
The cache is only stored in memory. The first time CreateActCtx is called, it adds an entry to the cache. Next time when the same CreateActCtx is called, the result is returned from the cache immediately, saving the expensive probing and xml parsing. The cache is lost when the machine reboots.
5. Cache Key
The activation context stores the parsed content of all manifests in the full assembly binding closure. Ideally, the cache key should be the path of all the manifests, and their last modified time.
However, if Sxs uses that as the key to the cache, it means Sxs will have to do all the expensive probing, parsing, which makes the cache useless.
To make a compromise, Sxs chooses the path of the entry manifest of CreateActCtx and its last modified time as the key. This means, if one of its dependent assemblies has changed, it is necessary to “touch” (i.e. change the last modified time of) the entry manifest for Sxs to see the change.
Here is an example. You may have a manifest myapp.exe.manifest depending on VC80, and you decides to deploy vc80 privately. So you have a private Microsoft.VC80.CRT.manifest. In Vista, when you change Microsoft.VC80.CRT.manifest, in order for Sxs to see the change in this manifest, you need to change the last modified time of myapp.exe.manifest.
Re: [RESOLVED] Enabling ComCtl 6 in VB6 IDE with the manifest file no longer works in
Originally Posted by dilettante
The 24 is a MANIFEST resource type, and the VB6 add-in doesn't support adding them. The trick is to use a CUSTOM resource with ID #24, and when it saves as .RES it retains that... but by the time the EXE is created these become MANIFEST (24) type resources.
You can use ResHacker, etc. to open your compiled EXE and see that.
Yes, you are right. It still looks like "#24" in the native VB6 resource editor:
But when I open this exe say in VS 2017 to see its resources, I see this:
Re: [RESOLVED] Enabling ComCtl 6 in VB6 IDE with the manifest file no longer works in
It's similar to how the Declare statement can be used to Alias a DLL Export by ordinal.
Code:
Private Declare Function SetWindowSubclass Lib "comctl32" Alias "#410" (ByVal hWnd As Long, ByVal pfnSubclass As Long, ByVal uIdSubclass As ISubclass, ByVal dwRefData As Long) As Long