ビジュアルスタイルによるコントロールの描画


ビジュアルスタイルでコントロールの描画をするために uxtheme.dll の関数を使用します。
OSにdllが存在することを確認するため、リンカの設定で uxtheme.dll を遅延読み込み(/DELAYLOAD)に指定します。

基本的な描画の手順は次のようになります。
(1)OpenThemeData でテーマを開く。
(2)DrawThemeBackground で背景イメージを描画。
(3)GetThemeBackgroundContentRect でコントロールのコンテンツ領域を取得。
(4)DrawThemeText でテキストを描画。
(5)CloseThemeData でテーマを閉じる。


Sample code
#define _WIN32_WINNT 0x0501
#include <windows.h>
#include <tchar.h>
#include <uxtheme.h>
#include <tmschema.h>

#pragma comment(lib, "uxtheme.lib")

#define IDM_EXIT  101

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
bool IsThemingSupported();

HINSTANCE hInst;
LPCTSTR lpszAppName   = TEXT("MyApp");
LPCTSTR lpszAppTitle  = TEXT("MyApp");

int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
    MSG        msg = {0};
    HWND       hWnd;
    WNDCLASSEX wc = {0};
    
    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);
    UNREFERENCED_PARAMETER(nCmdShow);
    
    //メインウィンドウクラス登録
    wc.cbSize        = sizeof(WNDCLASSEX);
    wc.style         = 0;
    wc.lpfnWndProc   = WndProc;
    wc.cbClsExtra    = 0;
    wc.cbWndExtra    = 0;
    wc.hInstance     = hInstance;
    wc.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
    wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_WINDOW + 1);
    wc.lpszMenuName  = NULL;
    wc.lpszClassName = lpszAppName;
    wc.hIconSm       = NULL;
    if(RegisterClassEx(&wc) == 0) {
        return 0;
    }
    
    hInst = hInstance;
    
    //メニュー作成
    HMENU hMenu = CreateMenu();
    HMENU hPopMenu = CreatePopupMenu();
    AppendMenu(hPopMenu, MF_STRING, IDM_EXIT, TEXT("&Exit"));
    AppendMenu(hMenu, MF_POPUP | MF_STRING, reinterpret_cast<UINT_PTR>(hPopMenu), TEXT("&File"));
    
    //メインウインドウ作成
    hWnd = CreateWindow(lpszAppName, lpszAppTitle, WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
        NULL, hMenu, hInstance, NULL
    );
    if(hWnd == NULL) {
        return 0;
    }
    
    ShowWindow(hWnd, SW_SHOWDEFAULT);
    UpdateWindow(hWnd);
    
    //メイン メッセージ ループ
    while(GetMessage(&msg, NULL, 0, 0)) {
        TranslateMessage(&msg); 
        DispatchMessage(&msg);
    }
    return static_cast<int>(msg.wParam);
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    static bool isThemingSupported = IsThemingSupported();
    static HTHEME hThemeButton = NULL;
    
    switch(uMsg) {
        case WM_COMMAND:
            switch(LOWORD(wParam)) {
                case IDM_EXIT: //終了
                    SendMessage(hWnd, WM_CLOSE, 0, 0);
                    break;
            }
            break;
        case WM_CREATE:
            {
                if(isThemingSupported) {
                    hThemeButton = OpenThemeData(hWnd, L"BUTTON");
                }
            }
            break;
        case WM_PAINT:
            {
                PAINTSTRUCT ps;
                BeginPaint(hWnd, &ps);
                RECT rect = {100, 100, 200, 200};
                if(hThemeButton != NULL) {
                    //ビジュアルスタイル適用あり
                    HRESULT hr = DrawThemeBackground(hThemeButton, ps.hdc, BP_PUSHBUTTON, PBS_NORMAL, &rect, NULL);
                    if(SUCCEEDED(hr)) {
                        RECT contentRect;
                        hr = GetThemeBackgroundContentRect(hThemeButton, ps.hdc, BP_PUSHBUTTON, PBS_NORMAL, &rect, &contentRect);
                        if(SUCCEEDED(hr)) {
                            LPCWSTR pszText = L"button";
                            DrawThemeText(hThemeButton, ps.hdc, BP_PUSHBUTTON, PBS_NORMAL, pszText, lstrlenW(pszText),
                                DT_CENTER | DT_VCENTER | DT_SINGLELINE, 0, &contentRect);
                        }
                    }
                }
                else {
                    //ビジュアルスタイル適用なし
                    if(DrawFrameControl(ps.hdc, &rect, DFC_BUTTON, DFCS_BUTTONPUSH)) {
                        LPCTSTR pszText = TEXT("button");
                        SetBkMode(ps.hdc, TRANSPARENT);
                        DrawText(ps.hdc, pszText, lstrlen(pszText), &rect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
                    }
                }
                EndPaint(hWnd, &ps);
            }
            break;
        case WM_THEMECHANGED:
            {
                if(hThemeButton != NULL) {
                    CloseThemeData(hThemeButton);
                }
                if(isThemingSupported) {
                    hThemeButton = OpenThemeData(hWnd, L"BUTTON");
                }
            }
            break;
        case WM_DESTROY:
            {
                if(hThemeButton != NULL) {
                    CloseThemeData(hThemeButton);
                }
                PostQuitMessage(0);
            }
            break;
        default:
            return DefWindowProc(hWnd, uMsg, wParam, lParam);
    }
    return 0;
}

bool IsThemingSupported()
{
    HINSTANCE hThemeDll = LoadLibrary(TEXT("uxtheme.dll"));
    bool themingSupported = (hThemeDll != NULL);
    if(hThemeDll != NULL) {
        FreeLibrary(hThemeDll);
    }
    return themingSupported;
}

一覧メニューへ