How to use modern Windows controls instead of the old-style interface when compiling Win32 programs with MinGW

⌚Time: 2026-02-21 19:05:00

👨‍💻Author: Jack Ge

I wrote a simple Win32 form program and compiled and ran it using MinGW for testing.

#ifndef UNICODE
#define UNICODE
#endif

#include <windows.h>
#include <commctrl.h>   // Required for the progress bar control

// Global instance handle
HINSTANCE hInst;

// Control ID Definition
#define IDC_BUTTON_START    1001
#define IDC_PROGRESS        1002

// Function Declaration
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

// Program entry point
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
    // Store instance handle
    hInst = hInstance;

    // Initialize the common control library (needed for the progress bar)
    INITCOMMONCONTROLSEX icc = { sizeof(INITCOMMONCONTROLSEX), ICC_PROGRESS_CLASS| ICC_BAR_CLASSES };
    InitCommonControlsEx(&icc);

    // Register window class
    const WCHAR CLASS_NAME[] = L"SampleAppWindow";

    WNDCLASSW wc = { };
    wc.lpfnWndProc   = WndProc;
    wc.hInstance     = hInstance;
    wc.lpszClassName = CLASS_NAME;
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    wc.hCursor       = LoadCursorW(NULL, IDC_ARROW);

    if (!RegisterClassW(&wc)) {
        return 0;
    }

    // Create Window
    HWND hwnd = CreateWindowExW(
        0,
        CLASS_NAME,
        L"Simple Win32 Program",
        WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX & ~WS_THICKFRAME,
        CW_USEDEFAULT, CW_USEDEFAULT, 400, 200,
        NULL,
        NULL,
        hInstance,
        NULL
    );

    if (!hwnd) {
        return 0;
    }

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

    // Message Loop
    MSG msg;
    while (GetMessageW(&msg, NULL, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessageW(&msg);
    }

    return 0;
}

// Window Proc
LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
    switch (uMsg) {
    case WM_CREATE: {
        // Create Button
        HWND hButton = CreateWindowW(
            L"BUTTON",
            L"Start",
            WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON,
            50, 30, 100, 30,
            hwnd,
            (HMENU)IDC_BUTTON_START,
            hInst,
            NULL
        );

        // Creating a Progress Bar
        HWND hProgress = CreateWindowW(
            PROGRESS_CLASSW,
            NULL,
            WS_CHILD | WS_VISIBLE,
            50, 80, 280, 25,
            hwnd,
            (HMENU)IDC_PROGRESS,
            hInst,
            NULL
        );

        // Set progress bar range (0-100)
        SendMessageW(hProgress, PBM_SETRANGE, 0, MAKELPARAM(0, 100));
        // Set progress to 33%
        SendMessageW(hProgress, PBM_SETPOS, 33, 0);
        break;
    }

    case WM_COMMAND: {
        int wmId = LOWORD(wParam);
        // Handle button click
        if (wmId == IDC_BUTTON_START) {
            MessageBoxW(hwnd, L"Button clicked!", L"Info", MB_OK | MB_ICONINFORMATION);
        }
        break;
    }

    case WM_DESTROY: {
        PostQuitMessage(0);
        return 0;
    }
    }

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

To compile and run, you need to add linking parameters -lcomctl32

g++ t.cpp -lcomctl32
./a.exe

It displays an old Windows 95-style visual theme. How can i make it use modern visual style controls?

First, you need to make sure common controls are initialized.

INITCOMMONCONTROLSEX icc;
// Initialise common controls.
icc.dwSize = sizeof(icc);
icc.dwICC = ICC_WIN95_CLASSES;
InitCommonControlsEx(&icc);

I registered the progress bar control and the button control in the example, and there is no problem.

// Initialize the common control library (needed for the progress bar)
INITCOMMONCONTROLSEX icc = { sizeof(INITCOMMONCONTROLSEX), ICC_PROGRESS_CLASS| ICC_BAR_CLASSES };
InitCommonControlsEx(&icc);

This table shows the meanings of different control flags, which come from:https://learn.microsoft.com/en-us/windows/win32/api/commctrl/ns-commctrl-initcommoncontrolsex?redirectedfrom=MSDN

Value Meaning
ICC_ANIMATE_CLASS 0x00000080 Load animate control class.
ICC_BAR_CLASSES 0x00000004 Load toolbar, status bar, trackbar, and tooltip control classes.
ICC_COOL_CLASSES 0x00000400 Load rebar control class.
ICC_DATE_CLASSES 0x00000100 Load date and time picker control class.
ICC_HOTKEY_CLASS 0x00000040 Load hot key control class.
ICC_INTERNET_CLASSES 0x00000800 Load IP address class.
ICC_LINK_CLASS 0x00008000 Load a hyperlink control class.
ICC_LISTVIEW_CLASSES 0x00000001 Load list-view and header control classes.
ICC_NATIVEFNTCTL_CLASS 0x00002000 Load a native font control class.
ICC_PAGESCROLLER_CLASS 0x00001000 Load pager control class.
ICC_PROGRESS_CLASS 0x00000020 Load progress bar control class.
ICC_STANDARD_CLASSES 0x00004000 Load one of the intrinsic User32 control classes. The user controls include button, edit, static, listbox, combobox, and scroll bar.
ICC_TAB_CLASSES 0x00000008 Load tab and tooltip control classes.
ICC_TREEVIEW_CLASSES 0x00000002 Load tree-view and tooltip control classes.
ICC_UPDOWN_CLASS 0x00000010 Load up-down control class.
ICC_USEREX_CLASSES 0x00000200 Load ComboBoxEx class.
ICC_WIN95_CLASSES 0x000000FF Load animate control, header, hot key, list-view, progress bar, status bar, tab, tooltip, toolbar, trackbar, tree-view, and up-down control classes.

I need to create a file named "[application name].exe.manifest" in the same directory as the program. For example, if my program is a.exe, I should create a file called a.exe.manifest. Then edit the following content.

<?xml version="1.0" encoding="utf-8" standalone="yes"?>

<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
  <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
    <application>
      <!-- Supports Windows Vista / Server 2008 -->
      <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
      <!-- Supports Windows 7 / Server 2008 R2 -->
      <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
      <!-- Supports Windows 8 / Server 2012 -->
      <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
      <!-- Supports Windows 8.1 / Server 2012 R2 -->
      <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
      <!-- Supports Windows 10 -->
      <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
    </application>
  </compatibility>
  <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
    <security>
      <requestedPrivileges>
        <requestedExecutionLevel level="asInvoker" uiAccess="false"/>
      </requestedPrivileges>
    </security>
  </trustInfo>
  <dependency>
    <dependentAssembly>
      <assemblyIdentity type="Win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" language="*"/>
    </dependentAssembly>
  </dependency>
</assembly>

Then recompile and run, and you can get modern-style controls.

I referred to this address:https://www.transmissionzero.co.uk/computing/win32-apps-with-mingw/


If you don't want the program directory to include a manifest file with the same name, you can also compile the manifest file into the program. The method is:

Create a test.manifest file. Enter the same content as the previous manifest file. This is the manifest file that needs to be embedded in the program.

Create a resource.rc file. Enter the following content, specifying the path to the test.manifest file.

#include <windows.h>

//if not include windows.h
//#define RT_MANIFEST 24 

#define CREATEPROCESS_MANIFEST_RESOURCE_ID 1
CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "test.manifest"

The Windows operating system automatically looks for a resource of type RT_MANIFEST with ID 1 when loading a program to use as the application's default manifest. Therefore, no other changes are needed.

Use windres to compile resource.rc to generate an object file

windres resource.rc -o resource.o

Use gcc to compile the program and generate an object file

g++ -c t.cpp

Last link

g++ -o a.exe t.o resource.o -lcomctl32

Programs generated this way can display modern-style controls, and they do not require a external manifest file at runtime.