How to enable visual styles without a manifest
Asked Answered
F

3

19

According to the docs:

"If you want your application to use ComCtl32.dll version 6, you must add an application manifest or compiler directive to specify that version 6 should be used if it is available."

Notice the logical OR above? So what is this mysterious compiler directive?

I've got a native Win32 C++ application that is wholly contained in a single .cpp file. There are no resource files, manifest files, etc. I'd like to keep it that way, but I would also like to use visual styles.

Floury answered 29/11, 2010 at 21:57 Comment(0)
V
20

If you're using Visual Studio, you can add this line to your stdafx.cpp for example:

#pragma comment(linker,"\"/manifestdependency:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
Volleyball answered 29/11, 2010 at 22:2 Comment(0)
C
34

There's actually a third way with no manifests whatsoever, though it's rather hacky:

#include <windows.h>

// NOTE: It is recommended that you delay-load ComCtl32.dll (/DelayLoad:ComCtl32.dll)
// and that you ensure this code runs before GUI components are loaded.
// Otherwise, you may get weird issues, like black backgrounds in icons in image lists.
ULONG_PTR EnableVisualStyles(VOID)
{
    TCHAR dir[MAX_PATH];
    ULONG_PTR ulpActivationCookie = FALSE;
    ACTCTX actCtx =
    {
        sizeof(actCtx),
        ACTCTX_FLAG_RESOURCE_NAME_VALID
            | ACTCTX_FLAG_SET_PROCESS_DEFAULT
            | ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID,
        TEXT("shell32.dll"), 0, 0, dir, (LPCTSTR)124
    };
    UINT cch = GetSystemDirectory(dir, sizeof(dir) / sizeof(*dir));
    if (cch >= sizeof(dir) / sizeof(*dir)) { return FALSE; /*shouldn't happen*/ }
    dir[cch] = TEXT('\0');
    ActivateActCtx(CreateActCtx(&actCtx), &ulpActivationCookie);
    return ulpActivationCookie;
}
Contaminant answered 4/5, 2012 at 6:57 Comment(9)
So this will break the day Microsoft changes the resource ID 124 to some other value in some future version of Windows.Heer
@MichaelWalz: Yes, hence why it's hacky.Contaminant
I try this code in win10 but ActivateActCtx return 0 and last error show ERROR_INVALID_PARAMETERCrossopterygian
@herzlshemuelian the only possible invalid parameter would be the HANDLE returned by CreateActCtx(), which returns INVALID_HANDLE_VALUE on failure. If CreateActCtx() fails, use GetLastError() to find out why (maybe the resource ID changed in Win10? This code works in Win7). Also, if CreateActCtx() succeeds, this code leaks the HANDLE. You need to call ReleaseActCtx() when you are finished using the activation context, but this code doesn't save the HANDLE anywhere.Guerrero
It appears that CreateActCtx is always going to use a manifest at some point. In this case, it's grabbing resource #124 from Shell32.dll, which happens to be a Manifest resource. Between Windows XP and Windows 10, resource #124 has consistently been the manifest file.Portecochere
Furthermore, using CreateActCtx is not "Hacky", it's what all Windows Forms programs use to enable visual styles. It uses resource #101 (a manifest) from System.Windows.Forms.dll.Portecochere
Wow, nevermind previous comment, it works like a charm! But it doesn't work with the tab controls, that isn't using new theme. what am I missing? imgur.com/EAQXIozKaolin
@Jack: Not sure unfortunately.Contaminant
Could someone explain what this code actually do?Shofar
V
20

If you're using Visual Studio, you can add this line to your stdafx.cpp for example:

#pragma comment(linker,"\"/manifestdependency:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
Volleyball answered 29/11, 2010 at 22:2 Comment(0)
S
10

If you had kept reading, you would have found the answer:

If you are using Microsoft Visual C++ 2005 or later, you can add the following compiler directive to your source code instead of manually creating a manifest. For readability, the directive is broken into two lines here.

#pragma comment(linker,"\"/manifestdependency:type='win32' name='Microsoft.Windows.Common-Controls' 
version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
Surprising answered 29/11, 2010 at 22:4 Comment(2)
LOL, I did open that link, but skimmed right past that line. It looked like it was entirely about manifests.Floury
The question (for OCD types) still remains over the above instead of: If one has already included a manifest for other things, does the above still work? A: If we read "manually creating a manifest" as "manually creating a manifest specifically for this purpose," yes.Maisel

© 2022 - 2024 — McMap. All rights reserved.