17

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.

Fizz
  • 4,782
  • 1
  • 24
  • 51
Tergiver
  • 14,171
  • 3
  • 41
  • 68

3 Answers3

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;
}
user541686
  • 205,094
  • 128
  • 528
  • 886
  • 1
    So this will break the day Microsoft changes the resource ID 124 to some other value in some future version of Windows. – Jabberwocky May 11 '17 at 08:56
  • 2
    @MichaelWalz: Yes, hence why it's hacky. – user541686 May 11 '17 at 09:05
  • I try this code in win10 but ActivateActCtx return 0 and last error show ERROR_INVALID_PARAMETER – herzl shemuelian Aug 23 '18 at 11:36
  • 1
    @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. – Remy Lebeau Aug 23 '18 at 17:00
  • 2
    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. – Dwedit May 12 '20 at 03:25
  • 2
    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. – Dwedit May 12 '20 at 03:33
  • 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? https://imgur.com/EAQXIoz – Jack Jan 23 '21 at 17:20
  • @Jack: Not sure unfortunately. – user541686 Jan 23 '21 at 21:47
  • Could someone explain what this code actually do? – Anton Agapov Jul 08 '22 at 18:07
18

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='*'\"")
Simon Mourier
  • 132,049
  • 21
  • 248
  • 298
8

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='*'\"")
John Dibling
  • 99,718
  • 31
  • 186
  • 324
  • LOL, I did open that link, but skimmed right past that line. It looked like it was entirely about manifests. – Tergiver Nov 29 '10 at 22:08
  • 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. – Laurie Stearn Mar 08 '18 at 04:11