PowerBASIC Users Meeting Point
EnableVisualStyles.bas - Printable Version

+- PowerBASIC Users Meeting Point (https://pump.richheimer.de)
+-- Forum: User to User Discussions (https://pump.richheimer.de/forumdisplay.php?fid=3)
+--- Forum: Source Code Library (https://pump.richheimer.de/forumdisplay.php?fid=8)
+--- Thread: EnableVisualStyles.bas (/showthread.php?tid=145)



EnableVisualStyles.bas - Borje Hagsten - 24.10.2026

Don't remember if anyone posted this kind of function in any of the old - now gone - forums, so here it is. Works for me in Windows 10 - hopefully also in later versions. To be compiled with PB/Win 10. Some comments explain.

Code:
'======================================================================
' Small example of how to enable visual styles in CommCtrl.dll v.6 via
' code instead of using manifest file in resource. Maybe not so useful,
' since doing it via xptheme.xml manifest in resource is easy, but here
' it is anyway. Public Domain by Borje Hagsten October 24, 2026.
'
' Added: Made a correction to deactivation via SUB DisableVisualStyles,
'        where FreeeLibrary and ReleaseActCtx was added.
'        Thank you Stanley Durham for pointing this out.
'======================================================================
#COMPILE EXE
#DIM ALL
'--------------------------------------------------------------------
%UNICODE = 1
#INCLUDE "WIN32API.INC"
'--------------------------------------------------------------------
%IDC_TEXTBOX1 = 531

GLOBAL ghActCtx, gCookie, ghShell32 AS LONG  ' need to store these as global.

'======================================================================
FUNCTION PBMAIN () AS LONG
  LOCAL hDlg AS LONG

  EnableVisualStyles() 'Activate at entry

  DIALOG NEW 0, "EnableVisualStyles",,, 185, 65, %WS_CAPTION OR %WS_SYSMENU OR _
                                                 %WS_MINIMIZEBOX, 0 TO hDlg
  DIALOG SET COLOR hDlg, -1, RGB(196, 196, 196)
  '------------------------------------------------------------------
  CONTROL ADD TEXTBOX, hDlg, %IDC_TEXTBOX1, "TextBox1", 5, 5, 100, 55
  CONTROL ADD BUTTON, hDlg, %IDCANCEL, "&Ok", 110, 46, 70, 14

  '------------------------------------------------------------------
  DIALOG SHOW MODAL hDlg  ' no callback - just a demo of how to..

  IF gCookie THEN DisableVisualStyles ' Deactivate at exit

END FUNCTION

'=================================================================================
' Enable visual styles in CommCtrl.dll v.6, using manifest resource in shell32.dll
'---------------------------------------------------------------------------------
FUNCTION EnableVisualStyles() AS DWORD

  LOCAL aCtx AS ACTCTX

#IF %DEF(%UNICODE)
  LOCAL szSys AS WSTRINGZ * %MAX_PATH
#ELSE
  LOCAL szSys AS ASCIIZ * %MAX_PATH
#ENDIF

  GetSystemDirectory szSys, SIZEOF(szSys)    ' Need path to shell32.dll

  aCtx.cbSize  = SIZEOF(ACTCTX)
  aCtx.dwFlags = %ACTCTX_FLAG_RESOURCE_NAME_VALID OR _
                 %ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID OR _
                 %ACTCTX_FLAG_HMODULE_VALID
  aCtx.hModule = LoadLibrary("shell32.dll")  ' Use the manifest resource in shell32.dll
  aCtx.lpResourceName = 124                  ' Manifest resource name
  aCtx.lpAssemblyDirectory = VARPTR(szSys)

  ghShell32 = aCtx.hModule
  ghActCtx  = CreateActCtx(aCtx)  'push the specified activation context to the top of the activation stack

  IF ghActCtx <> %INVALID_HANDLE_VALUE THEN   'vs.hActCtx = dwRes, &vs.cookie = dwCookie, vs.hShell32 = aCtx.hModule
     ActivateActCtx(ghActCtx, gCookie)
  END IF

  FUNCTION = gCookie
END FUNCTION

'=================================================================================
' Disable visual styles
'---------------------------------------------------------------------------------
SUB DisableVisualStyles
  IF gCookie THEN DeactivateActCtx(0, gCookie)
  IF NOT ghActCtx = %INVALID_HANDLE_VALUE THEN ReleaseActCtx(ghActCtx)
  IF ghShell32 THEN FreeLibrary(ghShell32)
END SUB



RE: EnableVisualStyles.bas - Stanley Durham - 24.10.2026

Cold blooded!
I had to give it a shot. x86_6 GCC version
Command line:
gcc EnableVisualStyles.c -o EnableVisualStyles.exe -mwindows -lcomctl32 -lgdi32 -luser32
DeepSeek conversion of code; I wouldn’t have a clue how to do it.
---
Added Note: Maybe I shouldn’t have put this here. Fill free to delete.

Code:
// gcc EnableVisualStyles.c -o EnableVisualStyles.exe -mwindows -lcomctl32 -lgdi32 -luser32
// targets x86_6
#ifndef UNICODE
#define UNICODE
#endif
#ifndef _UNICODE
#define _UNICODE
#endif

#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <commctrl.h>

#define IDC_TEXTBOX1 531

static HFONT g_hFont;

typedef struct
{
    HANDLE    hActCtx;
    ULONG_PTR cookie;
    HMODULE   hShell32;
} VISUAL_STYLES;

static VISUAL_STYLES EnableVisualStyles(void)
{
    WCHAR      szSys[MAX_PATH];
    ACTCTXW    aCtx;
    VISUAL_STYLES vs;

    vs.hActCtx  = INVALID_HANDLE_VALUE;
    vs.cookie   = 0;
    vs.hShell32 = NULL;

    if (!GetSystemDirectoryW(szSys, MAX_PATH))
        return vs;

    ZeroMemory(&aCtx, sizeof(aCtx));
    aCtx.cbSize              = sizeof(aCtx);
    aCtx.dwFlags             = ACTCTX_FLAG_RESOURCE_NAME_VALID
                             | ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID
                             | ACTCTX_FLAG_HMODULE_VALID;
    aCtx.hModule             = LoadLibraryW(L"shell32.dll");
    aCtx.lpResourceName      = MAKEINTRESOURCEW(124);
    aCtx.lpAssemblyDirectory = szSys;

    if (!aCtx.hModule)
        return vs;

    vs.hShell32 = aCtx.hModule;
    vs.hActCtx  = CreateActCtxW(&aCtx);

    if (vs.hActCtx != INVALID_HANDLE_VALUE)
        ActivateActCtx(vs.hActCtx, &vs.cookie);

    return vs;
}

static void DisableVisualStyles(VISUAL_STYLES *vs)
{
    if (vs->cookie)
        DeactivateActCtx(0, vs->cookie);
    if (vs->hActCtx != INVALID_HANDLE_VALUE)
        ReleaseActCtx(vs->hActCtx);
    if (vs->hShell32)
        FreeLibrary(vs->hShell32);

    vs->cookie   = 0;
    vs->hActCtx  = INVALID_HANDLE_VALUE;
    vs->hShell32 = NULL;
}

static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch (msg)
    {
    case WM_CREATE:
        {
            HINSTANCE hInst = (HINSTANCE)GetWindowLongPtrW(hwnd, GWLP_HINSTANCE);
            HWND hEdit, hOk;

            hEdit = CreateWindowExW(WS_EX_CLIENTEDGE, L"EDIT", L"TextBox1",
                WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_VSCROLL |
                ES_LEFT | ES_MULTILINE | ES_AUTOVSCROLL,
                10, 10, 150, 55, hwnd, (HMENU)(INT_PTR)IDC_TEXTBOX1, hInst, NULL);

            hOk = CreateWindowExW(0, L"BUTTON", L"&Ok",
                WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_DEFPUSHBUTTON,
                172, 54, 88, 26, hwnd, (HMENU)IDCANCEL, hInst, NULL);

            SendMessageW(hEdit, WM_SETFONT, (WPARAM)g_hFont, TRUE);
            SendMessageW(hOk,   WM_SETFONT, (WPARAM)g_hFont, TRUE);

            SetFocus(hEdit);
        }
        return 0;

    case WM_COMMAND:
        if (LOWORD(wParam) == IDCANCEL)
            SendMessageW(hwnd, WM_CLOSE, 0, 0);
        return 0;

    case WM_CLOSE:
        DestroyWindow(hwnd);
        return 0;

    case WM_DESTROY:
        if (g_hFont)
        {
            DeleteObject(g_hFont);
            g_hFont = NULL;
        }
        PostQuitMessage(0);
        return 0;
    }

    return DefWindowProcW(hwnd, msg, wParam, lParam);
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
                   LPSTR pCmdLine, int nCmdShow)
{
    VISUAL_STYLES  vs;
    WNDCLASSEXW    wc;
    INITCOMMONCONTROLSEX icc;
    NONCLIENTMETRICSW ncm;
    HWND  hwnd;
    MSG   msg;
    RECT  rc;
    DWORD style = WS_OVERLAPPEDWINDOW & ~(WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX);

    (void)hPrevInstance;
    (void)pCmdLine;

    vs = EnableVisualStyles();
    if (vs.cookie)
    {
        icc.dwSize = sizeof(icc);
        icc.dwICC  = ICC_STANDARD_CLASSES;
        InitCommonControlsEx(&icc);
    }

    ncm.cbSize = sizeof(ncm);
    if (SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0))
        g_hFont = CreateFontIndirectW(&ncm.lfMessageFont);
    if (!g_hFont)
        g_hFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT);

    ZeroMemory(&wc, sizeof(wc));
    wc.cbSize        = sizeof(wc);
    wc.style         = CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc   = WndProc;
    wc.hInstance     = hInstance;
    wc.hIcon         = LoadIconW(NULL, IDI_APPLICATION);
    wc.hIconSm       = wc.hIcon;
    wc.hCursor       = LoadCursorW(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
    wc.lpszClassName = L"EnableVisualStylesDemo";

    if (!RegisterClassExW(&wc))
    {
        DisableVisualStyles(&vs);
        return 1;
    }

    rc.left = 0; rc.top = 0; rc.right = 270; rc.bottom = 90;
    AdjustWindowRectEx(&rc, style, FALSE, WS_EX_CONTROLPARENT);

    hwnd = CreateWindowExW(WS_EX_CONTROLPARENT, wc.lpszClassName,
        L"EnableVisualStyles", style, CW_USEDEFAULT, CW_USEDEFAULT,
        rc.right - rc.left, rc.bottom - rc.top,
        NULL, NULL, hInstance, NULL);

    if (!hwnd)
    {
        DisableVisualStyles(&vs);
        return 1;
    }

    ShowWindow(hwnd, nCmdShow);
    UpdateWindow(hwnd);

    while (GetMessageW(&msg, NULL, 0, 0) > 0)
    {
        if (!IsDialogMessageW(hwnd, &msg))
        {
            TranslateMessage(&msg);
            DispatchMessageW(&msg);
        }
    }

    DisableVisualStyles(&vs);

    return (int)msg.wParam;
}



RE: EnableVisualStyles.bas - Borje Hagsten - 24.10.2026

Thank you, Stanley. It helped me realise I had missed a few things, like FreeLibrary and ReleaseActCtx, so PB code in first posting has been updated.


RE: EnableVisualStyles.bas - Stanley Durham - 24.10.2026

(5 hours ago)Borje Hagsten Wrote: Thank you, Stanley. It helped me realise I had missed a few things, like FreeLibrary and ReleaseActCtx, so  PB code in first posting has been updated.

DeepSeek didn't get on first try, so you're even.


RE: EnableVisualStyles.bas - José Roca - 24.10.2026

I think there is a common misconception here about activation contexts and visual styles.

The activation context does not need to remain active for the entire lifetime of the application in order for visual styles to keep working.

What actually matters is that the activation context is active when Windows loads and initializes the version 6 Common Controls (ComCtl32.dll). Once the themed controls have been created, deactivating the activation context does not suddenly "turn off" visual styles for controls that already exist.

In other words, the activation context is used to tell the Side-by-Side loader which version of the Common Controls library should be used. It is not a permanent switch that must stay enabled as long as the application is running.

For that reason, my implementation in FreeBasic simply:

- Creates the activation context.
- Activates it.
- Lets Windows load the themed Common Controls v6.
- Immediately deactivates and releases the activation context.

After that, the controls continue to use visual styles normally.

Keeping the activation context active for the entire process is only necessary if you intend to create additional objects later that must also be created under that same activation context. For the simple goal of enabling themed Common Controls, activating it temporarily is sufficient.

This is why the following FreeBasic code activates the context and immediately deactivates/releases it:

ActivateActCtx(hActCtx, @activationCookie)
 
DeactivateActCtx(0, activationCookie)
ReleaseActCtx(hActCtx)

and the application still gets visual styles correctly.

Conceptually, it is very similar to having an external manifest: the manifest influences how the process is initialized and which assemblies are selected, but Windows does not continuously consult it afterwards to decide whether already-created controls should remain themed.

The important point is that visual styles are a property of the Common Controls v6 implementation that gets loaded, not of the current activation state of the activation context stack after the controls have already been created.

This is the function that I use in FreeBasic:

Code:
' ========================================================================================
' * Enables visual styles without using a manifest in the application.
' ========================================================================================
PUBLIC FUNCTION EnableVisualStyles () AS BOOLEAN

  ' // Fill the ACTCTXW structure
  DIM actCtx AS ACTCTXW
  actCtx.cbSize = SIZEOF(ACTCTXW)
  actCtx.dwFlags = ACTCTX_FLAG_RESOURCE_NAME_VALID OR ACTCTX_FLAG_SET_PROCESS_DEFAULT OR ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID

  ' // Get system directory
  DIM systemDir AS WSTRING * MAX_PATH
  DIM cch AS UINT = GetSystemDirectoryW(@systemDir, MAX_PATH)
  IF cch >= MAX_PATH THEN RETURN FALSE  ' Ensure buffer is not exceeded
  systemDir[cch] = ASC("\")  ' Append backslash
  actCtx.lpAssemblyDirectory = @systemDir
  DIM wszSource AS WSTRING * MAX_PATH = systemDir & "shell32.dll"
  actCtx.lpSource = CAST(WSTRING PTR, @wszSource)  ' Use shell32.dll's manifest
  actCtx.lpResourceName = CAST(WSTRING PTR, 124)  ' Resource ID for the manifest (IDR_MANIFEST = 1, RT_MANIFEST = 24)

  ' // Create the activation context
  DIM hActCtx AS HANDLE = CreateActCtxW(@actCtx)
  IF hActCtx = INVALID_HANDLE_VALUE THEN RETURN FALSE
  ' // Activate the context
  DIM activationCookie AS ULONG_PTR
  ActivateActCtx(hActCtx, @activationCookie)

  ' // Deactivate and release the context
  DeactivateActCtx(0, activationCookie)
  ReleaseActCtx(hActCtx)
  RETURN TRUE

END FUNCTION
' ========================================================================================



RE: EnableVisualStyles.bas - Stanley Durham - 25.10.2026

This day and age, this is what I would do.
DeepSeek prompt:
---
Compiler: MSYS2 MinGW-w64 ucrt64 GCC C
source: C:\CCode\EnableVisualStyles\App.c (doesn't exist)
write a simple test app with some controls in it
use python to make icons of a bird
put the icons and visual style manifest in the resource file
give me the command line to compile it
---
Done deal with beautiful high-res icon with rounded corners. Just tell it what kind of icon you want.
If you use AI, you should have python installed. That's what it uses to build everything.