C++
Windows
C++11

Win32API C++11化計画

More than 1 year has passed since last update.

Win32APIにはANSI版とUnicode版の二種類あるものが多いですが、Cからでも利用できるようにするためか、どちらを使用するかの切り替えをオーバーロードを使わずプリプロセッサのマクロでどうにかしています。

Visual C++もC++11のサポートが揃ってきたこのご時世、折角なのでオーバーロードを使った物に書き換えてみようと思いました。

でも面倒なので自分が使っている範囲で気が向いたものだけやっていきます。思いつきでやってるのでC++11の仕様か14の仕様かとかは気にしてません。またVisual Studio 2017で試しているので2013や2015他では使えないものもあるかもしれません。

あしからずご了承ください。

引数にTCHAR型を受け取るもの

これは普通にオーバーロードすればいいですね。ただ利用者側の変更を極力するためにAPIの名前を変更したくありませんので、ANIS版かUnicode版かを切り替えているプリプロセッサのマクロをundefしておきます。

#undef LoadString
inline auto LoadString(HINSTANCE instance, UINT id, char* buffer, int buffer_length) {
    return LoadStringA(instance, id, buffer, buffer_length);
}
inline auto LoadString(HINSTANCE instance, UINT id, wchar_t* buffer, int buffer_length) {
    return LoadStringW(instance, id, buffer, buffer_length);
}

ついでなので文字列を受け取るためのバッファを引数に取るものは、配列を渡したらバッファの長さも自動的に指定されるようにしてしまいます。

template <typename xchar_t, size_t length>
inline auto LoadString(HINSTANCE instance, UINT id, xchar_t(&buffer)[length]) {
    return LoadString(instance, id, buffer, length);
}

も一つついでにstd::w?stringを返すような物も用意してしまいましょう。

template <typename xchar_t = TCHAR>
inline auto LoadString(HINSTANCE instance, UINT id) {
    using xstring = std::basic_string<xchar_t>;
    xstring buffer;
    size_t capacity = 256;
    while (true) {
        buffer.assign(capacity, '\0');
        size_t length = LoadString(instance, id, &buffer[0], capacity);
        if (length == 0) return xstring {};
        if (length < capacity) {
            buffer.resize(length);
            return buffer;
        }
        capacity += 256;
    }
}

inlineなのにちょっと長くなっちゃいましたけど、きっとコンパイラが良きに計らってくれるはず。

引数にTCHAR型が含まれない場合

Win32APIには引数にTCHAR型が含まれないのにANSI版とUnicode版に分かれているものがあります。

これらについては仕方が無いのでtemplate引数でどちらを使うかを指定してもらって、デフォルトはTCHARになるようにします。

#undef GetMessage
template <typename xchar_t = TCHAR>
auto GetMessage(LPMSG msg, HWND window, WPARAM wParam, LPARAM lParam);
template <>
inline auto GetMessage<char>(LPMSG msg, HWND window, WPARAM wParam, LPARAM lParam) {
    return ::GetMessageA(msg, window, wParam, lParam);
}
template <>
inline auto GetMessage<wchar_t>(LPMSG msg, HWND window, WPARAM wParam, LPARAM lParam) {
    return ::GetMessageW(msg, window, wParam, lParam);
}

定数のenum class化

引数に特定の定数しか指定できないようなAPIのために、定数をenum classとして定義します。

enum class syscolor : int {
    scrollbar = COLOR_SCROLLBAR,
    background = COLOR_BACKGROUND,
    activecaption = COLOR_ACTIVECAPTION,
    inactivecaption = COLOR_INACTIVECAPTION,
    menu = COLOR_MENU,
    window = COLOR_WINDOW,
    windowframe = COLOR_WINDOWFRAME,
    menutext = COLOR_MENUTEXT,
    windowtext = COLOR_WINDOWTEXT,
    captiontext = COLOR_CAPTIONTEXT,
    activeborder = COLOR_ACTIVEBORDER,
    inactiveborder = COLOR_INACTIVEBORDER,
    appworkspace = COLOR_APPWORKSPACE,
    highlight = COLOR_HIGHLIGHT,
    highlighttext = COLOR_HIGHLIGHTTEXT,
    btnface = COLOR_BTNFACE,
    btnshadow = COLOR_BTNSHADOW,
    graytext = COLOR_GRAYTEXT,
    btntext = COLOR_BTNTEXT,
    inactivecaptiontext = COLOR_INACTIVECAPTIONTEXT,
    btnhighlight = COLOR_BTNHIGHLIGHT,
    _3ddkshadow = COLOR_3DDKSHADOW,
    _3dlight = COLOR_3DLIGHT,
    infotext = COLOR_INFOTEXT,
    infobk = COLOR_INFOBK,
    hotlight = COLOR_HOTLIGHT,
    gradientactivecaption = COLOR_GRADIENTACTIVECAPTION,
    gradientinactivecaption = COLOR_GRADIENTINACTIVECAPTION,
    menuhilight = COLOR_MENUHILIGHT,
    menubar = COLOR_MENUBAR,
    desktop = COLOR_DESKTOP,
    _3dface = COLOR_3DFACE,
    _3dshadow = COLOR_3DSHADOW,
    _3dhighlight = COLOR_3DHIGHLIGHT,
    _3dhilight = COLOR_3DHILIGHT,
    btnhilight = COLOR_BTNHILIGHT,
};

inline auto GetSysColor(syscolor sc) {
    return ::GetSysColor(static_cast<std::underlying_type_t<syscolor>>(sc));
}

inline auto GetSysColorBrush(syscolor sc) {
    return ::GetSysColorBrush(static_cast<std::underlying_type_t<syscolor>>(sc));
}

enum classにしてしまうと利用者側に修正が必要になってしまいますが(上記だと例えばCOLOR_MENUHILIGHTsyscolor::menuhilightに書き換える必要がある)、GetSysColor(syscolor::まで入力すれば、定義されたシンボルだけがIntellisenceの補完候補として並ぶので
入力が楽になります。

型が曖昧なAPIを厳密に

Win32APIには色んな値を返せるように引数や返値の型がlongになっているものの、別の引数の値によってポインタ型としてキャストする必要のあるものがあります。それらを別の名前で用意してキャストもしてしまいます。

ここで用意するAPIの名前は元々あるAPIと区別するために小文字から始めることにします。

template <typename xchar_t = TCHAR>
inline auto getWindowProc(HWND window) {
    return reinterpret_cast<WNDPROC>(GetWindowLongPtr<xchar_t>(window, GWLP_WNDPROC));
}
template <typename xchar_t = TCHAR>
inline auto setWindowProc(HWND window, WNDPROC wndproc) {
    return reinterpret_cast<WNDPROC>(SetWindowLongPtr<xchar_t>(window, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(wndproc)));
}
template <typename xchar_t = TCHAR>
inline auto getWindowInstance(HWND window) {
    return reinterpret_cast<HINSTANCE>(GetWindowLongPtr<xchar_t>(window, GWLP_HINSTANCE));
}

使用例

新規プロジェクトを作成してWindowsデスクトップアプリケーションを選択して生成されたサンプルコードを、このヘッダを使った物に書き換えてみます。

WindowsProject.cpp
// Win32Project1.cpp : アプリケーションのエントリ ポイントを定義します。
//

#include "stdafx.h"
#include "resource.h"

#include "Windows.hpp"

int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE, LPTSTR, int nCmdShow) {
    // windowクラスの登録
    auto atom = RegisterClassEx(WNDCLASSEX {
        sizeof(WNDCLASSEX),
        CS_HREDRAW | CS_VREDRAW,
        [] (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) -> LRESULT {
            switch (message) {
            case WM_COMMAND:
                // 選択されたメニューの解析:
                switch (LOWORD(wParam)) {
                case IDM_ABOUT:
                    DialogBox(getWindowInstance(hWnd), IDD_ABOUTBOX, hWnd, [] (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) -> INT_PTR {
                        UNREFERENCED_PARAMETER(lParam);
                        switch (message) {
                        case WM_INITDIALOG:
                            return TRUE;

                        case WM_COMMAND:
                            switch (LOWORD(wParam)) {
                            case IDOK:
                            case IDCANCEL:
                                EndDialog(hDlg, LOWORD(wParam));
                                return TRUE;
                            }
                            break;
                        }
                        return FALSE;
                    });
                    break;
                case IDM_EXIT:
                    DestroyWindow(hWnd);
                    break;
                default:
                    return DefWindowProc(hWnd, message, wParam, lParam);
                }
                break;
            case WM_PAINT:
                {
                    PaintDC dc {hWnd};
                    // TODO: HDC を使用する描画コードをここに追加してください...
                }
                break;
            case WM_DESTROY:
                PostQuitMessage(0);
                break;
            default:
                return DefWindowProc(hWnd, message, wParam, lParam);
            }
            return 0;
        },
        0,
        0,
        hInstance,
        LoadIcon(hInstance, IDI_WIN32PROJECT1),
        LoadCursor(nullptr, IDC_ARROW),
        getStaticSysColorBrush(syscolor::window),
        MAKEINTRESOURCE(IDC_WIN32PROJECT1),
        LoadString(hInstance, IDC_WIN32PROJECT1).c_str(),
        LoadIcon(hInstance, IDI_SMALL),
    });

    // アプリケーションの初期化を実行します:
    auto title = LoadString(hInstance, IDS_APP_TITLE);
    HWND hWnd = CreateWindow(MAKEINTATOM(atom), title, WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, nullptr, nullptr, hInstance, nullptr);
    if (!hWnd) return 0;

    ShowWindow(hWnd, nCmdShow);
    UpdateWindow(hWnd);

    auto hAccelTable = LoadAccelerators(hInstance, IDC_WIN32PROJECT1);

    MSG msg;
    // メイン メッセージ ループ:
    while (GetMessage(&msg, nullptr, 0, 0)) {
        if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }

    return (int) msg.wParam;
}

サンプルコードでは複数の関数に分かれていたものが一つにまとまってスッキリ(スッキリ?)。

コード

Windows.hpp
#pragma once

#include <Windows.h>

#include <string>
#include <type_traits>

#undef MAKEINTRESOURCE
template <typename xchar_t = TCHAR>
inline constexpr auto MAKEINTRESOURCE(UINT id) {
    return reinterpret_cast<const xchar_t*>(id);
}

#undef MAKEINTATOM
template <typename xchar_t = TCHAR>
inline constexpr auto MAKEINTATOM(ATOM atom) {
    return reinterpret_cast<const xchar_t*>(atom);
}

enum class syscolor : int {
    scrollbar = COLOR_SCROLLBAR,
    background = COLOR_BACKGROUND,
    activecaption = COLOR_ACTIVECAPTION,
    inactivecaption = COLOR_INACTIVECAPTION,
    menu = COLOR_MENU,
    window = COLOR_WINDOW,
    windowframe = COLOR_WINDOWFRAME,
    menutext = COLOR_MENUTEXT,
    windowtext = COLOR_WINDOWTEXT,
    captiontext = COLOR_CAPTIONTEXT,
    activeborder = COLOR_ACTIVEBORDER,
    inactiveborder = COLOR_INACTIVEBORDER,
    appworkspace = COLOR_APPWORKSPACE,
    highlight = COLOR_HIGHLIGHT,
    highlighttext = COLOR_HIGHLIGHTTEXT,
    btnface = COLOR_BTNFACE,
    btnshadow = COLOR_BTNSHADOW,
    graytext = COLOR_GRAYTEXT,
    btntext = COLOR_BTNTEXT,
    inactivecaptiontext = COLOR_INACTIVECAPTIONTEXT,
    btnhighlight = COLOR_BTNHIGHLIGHT,
    _3ddkshadow = COLOR_3DDKSHADOW,
    _3dlight = COLOR_3DLIGHT,
    infotext = COLOR_INFOTEXT,
    infobk = COLOR_INFOBK,
    hotlight = COLOR_HOTLIGHT,
    gradientactivecaption = COLOR_GRADIENTACTIVECAPTION,
    gradientinactivecaption = COLOR_GRADIENTINACTIVECAPTION,
    menuhilight = COLOR_MENUHILIGHT,
    menubar = COLOR_MENUBAR,
    desktop = COLOR_DESKTOP,
    _3dface = COLOR_3DFACE,
    _3dshadow = COLOR_3DSHADOW,
    _3dhighlight = COLOR_3DHIGHLIGHT,
    _3dhilight = COLOR_3DHILIGHT,
    btnhilight = COLOR_BTNHILIGHT,
};

inline auto GetSysColor(syscolor sc) {
    return ::GetSysColor(static_cast<std::underlying_type_t<syscolor>>(sc));
}

inline auto GetSysColorBrush(syscolor sc) {
    return ::GetSysColorBrush(static_cast<std::underlying_type_t<syscolor>>(sc));
}

inline constexpr auto getStaticSysColorBrush(syscolor sc) {
    return reinterpret_cast<HBRUSH>(static_cast<std::underlying_type_t<syscolor>>(sc) + 1);
}

#undef LoadString
inline auto LoadString(HINSTANCE instance, UINT id, char* buffer, int buffer_length) {
    return LoadStringA(instance, id, buffer, buffer_length);
}
inline auto LoadString(HINSTANCE instance, UINT id, wchar_t* buffer, int buffer_length) {
    return LoadStringW(instance, id, buffer, buffer_length);
}
template <typename xchar_t, size_t length>
inline auto LoadString(HINSTANCE instance, UINT id, xchar_t(&buffer)[length]) {
    return LoadString(instance, id, buffer, length);
}
template <typename xchar_t = TCHAR>
inline auto LoadString(HINSTANCE instance, UINT id) {
    using xstring = std::basic_string<xchar_t>;
    xstring buffer;
    size_t capacity = 256;
    while (true) {
        buffer.assign(capacity, '\0');
        size_t length = LoadString(instance, id, &buffer[0], capacity);
        if (length == 0) return xstring {};
        if (length < capacity) {
            buffer.resize(length);
            return buffer;
        }
        capacity += 256;
    }
}

#undef LoadAccelerators
inline auto LoadAccelerators(HINSTANCE hInstance, const char* id) {
    return LoadAcceleratorsA(hInstance, id);
}
inline auto LoadAccelerators(HINSTANCE hInstance, const wchar_t* id) {
    return LoadAcceleratorsW(hInstance, id);
}
template <typename xchar_t = TCHAR>
inline auto LoadAccelerators(HINSTANCE hInstance, UINT_PTR id) {
    return LoadAccelerators(hInstance, MAKEINTRESOURCE<xchar_t>(id));
}
#undef LoadIcon
inline auto LoadIcon(HINSTANCE hInstance, const char* id) {
    return LoadIconA(hInstance, id);
}
inline auto LoadIcon(HINSTANCE hInstance, const wchar_t* id) {
    return LoadIconW(hInstance, id);
}
template <typename xchar_t = TCHAR>
inline auto LoadIcon(HINSTANCE hInstance, UINT_PTR id) {
    return LoadIcon(hInstance, MAKEINTRESOURCE<xchar_t>(id));
}
#undef LoadCursor
inline auto LoadCursor(HINSTANCE hInstance, const char* id) {
    return LoadCursorA(hInstance, id);
}
inline auto LoadCursor(HINSTANCE hInstance, const wchar_t* id) {
    return LoadCursorW(hInstance, id);
}
template <typename xchar_t = TCHAR>
inline auto LoadCursor(HINSTANCE hInstance, UINT_PTR id) {
    return LoadCursor(hInstance, MAKEINTRESOURCE<xchar_t>(id));
}

#undef RegisterClass
inline auto RegisterClass(const WNDCLASSA* wc) {
    return ::RegisterClassA(wc);
}
inline auto RegisterClass(const WNDCLASSW* wc) {
    return ::RegisterClassW(wc);
}
inline auto RegisterClass(const WNDCLASSA& wc) {
    return RegisterClass(&wc);
}
inline auto RegisterClass(const WNDCLASSW& wc) {
    return RegisterClass(&wc);
}
#undef RegisterClassEx
inline auto RegisterClassEx(const WNDCLASSEXA* wc) {
    return ::RegisterClassExA(wc);
}
inline auto RegisterClassEx(const WNDCLASSEXW* wc) {
    return ::RegisterClassExW(wc);
}
inline auto RegisterClassEx(const WNDCLASSEXA& wc) {
    return RegisterClassEx(&wc);
}
inline auto RegisterClassEx(const WNDCLASSEXW& wc) {
    return RegisterClassEx(&wc);
}

#undef GetMessage
template <typename xchar_t = TCHAR>
auto GetMessage(LPMSG msg, HWND window, WPARAM wParam, LPARAM lParam);
template <>
inline auto GetMessage<char>(LPMSG msg, HWND window, WPARAM wParam, LPARAM lParam) {
    return ::GetMessageA(msg, window, wParam, lParam);
}
template <>
inline auto GetMessage<wchar_t>(LPMSG msg, HWND window, WPARAM wParam, LPARAM lParam) {
    return ::GetMessageW(msg, window, wParam, lParam);
}

#undef DispatchMessage
template <typename xchar_t = TCHAR>
auto DispatchMessage(const MSG* msg);
template <>
inline auto DispatchMessage<char>(const MSG* msg) {
    return ::DispatchMessageA(msg);
}
template <>
inline auto DispatchMessage<wchar_t>(const MSG* msg) {
    return ::DispatchMessageW(msg);
}

#undef TranslateAccelerator
template <typename xchar_t = TCHAR>
auto TranslateAccelerator(HWND window, HACCEL accel, LPMSG msg);
template <>
inline auto TranslateAccelerator<char>(HWND window, HACCEL accel, LPMSG msg) {
    return ::TranslateAcceleratorA(window, accel, msg);
}
template <>
inline auto TranslateAccelerator<wchar_t>(HWND window, HACCEL accel, LPMSG msg) {
    return ::TranslateAcceleratorW(window, accel, msg);
}

#undef CreateWindow
inline auto CreateWindow(const char* className, const char* windowName, DWORD style, int x, int y, int width, int height, HWND parent, HMENU menu, HINSTANCE instance, LPVOID lParam) {
    return ::CreateWindowExA(0, className, windowName, style, x, y, width, height, parent, menu, instance, lParam);
}
inline auto CreateWindow(const wchar_t* className, const wchar_t* windowName, DWORD style, int x, int y, int width, int height, HWND parent, HMENU menu, HINSTANCE instance, LPVOID lParam) {
    return ::CreateWindowExW(0, className, windowName, style, x, y, width, height, parent, menu, instance, lParam);
}
template <typename xchar_t>
inline auto CreateWindow(const xchar_t* className, const std::basic_string<xchar_t>& windowName, DWORD style, int x, int y, int width, int height, HWND parent, HMENU menu, HINSTANCE instance, LPVOID lParam) {
    return CreateWindow(className, windowName.c_str(), style, x, y, width, height, parent, menu, instance, lParam);
}
#undef CreateWindowEx
inline auto CreateWindowEx(DWORD exStyle, const char* className, const char* windowName, DWORD style, int x, int y, int width, int height, HWND parent, HMENU menu, HINSTANCE instance, LPVOID lParam) {
    return ::CreateWindowExA(exStyle, className, windowName, style, x, y, width, height, parent, menu, instance, lParam);
}
inline auto CreateWindowEx(DWORD exStyle, const wchar_t* className, const wchar_t* windowName, DWORD style, int x, int y, int width, int height, HWND parent, HMENU menu, HINSTANCE instance, LPVOID lParam) {
    return ::CreateWindowExW(exStyle, className, windowName, style, x, y, width, height, parent, menu, instance, lParam);
}
template <typename xchar_t>
inline auto CreateWindowEx(DWORD exStyle, const char* className, const std::basic_string<xchar_t>& windowName, DWORD style, int x, int y, int width, int height, HWND parent, HMENU menu, HINSTANCE instance, LPVOID lParam) {
    return CreateWindowEx(exStyle, className, windowName.c_str(), style, x, y, width, height, parent, menu, instance, lParam);
}

#undef DefWindowProc
template <typename xchar_t = TCHAR>
auto DefWindowProc(HWND window, UINT message, WPARAM wParam, LPARAM lParam);
template <>
inline auto DefWindowProc<char>(HWND window, UINT message, WPARAM wParam, LPARAM lParam) {
    return ::DefWindowProcA(window, message, wParam, lParam);
}
template <>
inline auto DefWindowProc<wchar_t>(HWND window, UINT message, WPARAM wParam, LPARAM lParam) {
    return ::DefWindowProcW(window, message, wParam, lParam);
}

#undef DialogBoxParam
inline auto DialogBoxParam(HINSTANCE instance, const char* templateName, HWND parent, DLGPROC dialogProc, LPARAM lParam) {
    return ::DialogBoxParamA(instance, templateName, parent, dialogProc, lParam);
}
inline auto DialogBoxParam(HINSTANCE instance, const wchar_t* templateName, HWND parent, DLGPROC dialogProc, LPARAM lParam) {
    return ::DialogBoxParamW(instance, templateName, parent, dialogProc, lParam);
}
template <typename xchar_t = TCHAR>
inline auto DialogBoxParam(HINSTANCE instance, UINT id, HWND parent, DLGPROC dialogProc, LPARAM lParam) {
    return DialogBoxParam(instance, MAKEINTRESOURCE<xchar_t>(id), parent, dialogProc, lParam);
}
#undef DialogBox
template <typename xchar_t>
inline auto DialogBox(HINSTANCE instance, const xchar_t* templateName, HWND parent, DLGPROC dialogProc) {
    return DialogBoxParam(instance, templateName, parent, dialogProc, 0L);
}
template <typename xchar_t = TCHAR>
inline auto DialogBox(HINSTANCE instance, UINT id, HWND parent, DLGPROC dialogProc) {
    return DialogBox(instance, MAKEINTRESOURCE<xchar_t>(id), parent, dialogProc);
}

#undef GetWindowLong
template <typename xchar_t = TCHAR>
auto GetWindowLong(HWND hWnd, int nIndex);
template <>
inline auto GetWindowLong<char>(HWND hWnd, int nIndex) {
    return ::GetWindowLongA(hWnd, nIndex);
}
template <>
inline auto GetWindowLong<wchar_t>(HWND hWnd, int nIndex) {
    return ::GetWindowLongW(hWnd, nIndex);
}
#undef SetWindowLong
template <typename xchar_t = TCHAR>
auto SetWindowLong(HWND hWnd, int nIndex, LONG value);
template <>
inline auto SetWindowLong<char>(HWND hWnd, int nIndex, LONG value) {
    return ::SetWindowLongA(hWnd, nIndex, value);
}
template <>
inline auto SetWindowLong<wchar_t>(HWND hWnd, int nIndex, LONG value) {
    return ::SetWindowLongW(hWnd, nIndex, value);
}

#undef GetWindowLongPtr
template <typename xchar_t = TCHAR>
auto GetWindowLongPtr(HWND hWnd, int nIndex);
template <>
inline auto GetWindowLongPtr<char>(HWND hWnd, int nIndex) {
    return ::GetWindowLongPtrA(hWnd, nIndex);
}
template <>
inline auto GetWindowLongPtr<wchar_t>(HWND hWnd, int nIndex) {
    return ::GetWindowLongPtrW(hWnd, nIndex);
}
#undef SetWindowLongPtr
template <typename xchar_t = TCHAR>
auto SetWindowLongPtr(HWND hWnd, int nIndex, LONG_PTR value);
template <>
inline auto SetWindowLongPtr<char>(HWND hWnd, int nIndex, LONG_PTR value) {
    return ::SetWindowLongPtrA(hWnd, nIndex, value);
}
template <>
inline auto SetWindowLongPtr<wchar_t>(HWND hWnd, int nIndex, LONG_PTR value) {
    return ::SetWindowLongPtrW(hWnd, nIndex, value);
}

#undef GetClassLong
template <typename xchar_t = TCHAR>
auto GetClassLong(HWND hWnd, int nIndex);
template <>
inline auto GetClassLong<char>(HWND hWnd, int nIndex) {
    return ::GetClassLongA(hWnd, nIndex);
}
template <>
inline auto GetClassLong<wchar_t>(HWND hWnd, int nIndex) {
    return ::GetClassLongW(hWnd, nIndex);
}
#undef SetClassLong
template <typename xchar_t = TCHAR>
auto SetClassLong(HWND hWnd, int nIndex, LONG value);
template <>
inline auto SetClassLong<char>(HWND hWnd, int nIndex, LONG value) {
    return ::SetClassLongA(hWnd, nIndex, value);
}
template <>
inline auto SetClassLong<wchar_t>(HWND hWnd, int nIndex, LONG value) {
    return ::SetClassLongW(hWnd, nIndex, value);
}

#undef GetClassLongPtr
template <typename xchar_t = TCHAR>
auto GetClassLongPtr(HWND hWnd, int nIndex);
template <>
inline auto GetClassLongPtr<char>(HWND hWnd, int nIndex) {
    return ::GetClassLongPtrA(hWnd, nIndex);
}
template <>
inline auto GetClassLongPtr<wchar_t>(HWND hWnd, int nIndex) {
    return ::GetClassLongPtrW(hWnd, nIndex);
}
#undef SetClassLongPtr
template <typename xchar_t = TCHAR>
auto SetClassLongPtr(HWND hWnd, int nIndex, LONG_PTR value);
template <>
inline auto SetClassLongPtr<char>(HWND hWnd, int nIndex, LONG_PTR value) {
    return ::SetClassLongPtrA(hWnd, nIndex, value);
}
template <>
inline auto SetClassLongPtr<wchar_t>(HWND hWnd, int nIndex, LONG_PTR value) {
    return ::SetClassLongPtrW(hWnd, nIndex, value);
}

template <typename xchar_t = TCHAR>
inline auto getWindowProc(HWND window) {
    return reinterpret_cast<WNDPROC>(GetWindowLongPtr<xchar_t>(window, GWLP_WNDPROC));
}
template <typename xchar_t = TCHAR>
inline auto setWindowProc(HWND window, WNDPROC wndproc) {
    return reinterpret_cast<WNDPROC>(SetWindowLongPtr<xchar_t>(window, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(wndproc)));
}
template <typename xchar_t = TCHAR>
inline auto getWindowInstance(HWND window) {
    return reinterpret_cast<HINSTANCE>(GetWindowLongPtr<xchar_t>(window, GWLP_HINSTANCE));
}
template <typename xchar_t = TCHAR>
inline auto getClassMenuName(HWND window) {
    return reinterpret_cast<const xchar_t*>(GetClassLongPtr<xchar_t>(window, GCLP_MENUNAME));
}
template <typename xchar_t = TCHAR>
inline auto getClassBackground(HWND window) {
    return reinterpret_cast<HBRUSH>(GetClassLongPtr<xchar_t>(window, GCLP_HBRBACKGROUND));
}
template <typename xchar_t = TCHAR>
inline auto getClassCursor(HWND window) {
    return reinterpret_cast<HCURSOR>(GetClassLongPtr<xchar_t>(window, GCLP_HCURSOR));
}
template <typename xchar_t = TCHAR>
inline auto getClassIcon(HWND window) {
    return reinterpret_cast<HICON>(GetClassLongPtr<xchar_t>(window, GCLP_HICON));
}
template <typename xchar_t = TCHAR>
inline auto getClassModule(HWND window) {
    return reinterpret_cast<HMODULE>(GetClassLongPtr<xchar_t>(window, GCLP_HMODULE));
}
template <typename xchar_t = TCHAR>
inline auto getClassWndProc(HWND window) {
    return reinterpret_cast<WNDPROC>(GetClassLongPtr<xchar_t>(window, GCLP_WNDPROC));
}
template <typename xchar_t = TCHAR>
inline auto getClassStyle(HWND window) {
    return GetClassLong<xchar_t>(window, GCL_STYLE);
}
template <typename xchar_t = TCHAR>
inline auto getClassAtom(HWND window) {
    return reinterpret_cast<ATOM>(GetClassLong<xchar_t>(window, GCW_ATOM));
}
template <typename xchar_t = TCHAR>
inline auto getClassIconSmall(HWND window) {
    return reinterpret_cast<HICON>(GetClassLongPtr<xchar_t>(window, GCLP_HICONSM));
}

#undef wsprintf
template <typename... Args>
inline auto wsprintf(char* buffer, const char* format, Args&&... args) {
    return wsprintfA(buffer, format, std::forward<Args>(args)...);
}
template <typename... Args>
inline auto wsprintf(wchar_t* buffer, const wchar_t* format, Args&&... args) {
    return wsprintfW(buffer, format, std::forward<Args>(args)...);
}

struct PaintDC : PAINTSTRUCT {
    const HDC hdc;
    const HWND window;
    PaintDC(HWND window):window(window), hdc(::BeginPaint(window, this)) {
    }
    ~PaintDC() {
        ::EndPaint(window, this);
    }
    operator HDC()const {
        return hdc;
    }
};

#undef OutputDebugString
inline void OutputDebugString(const char* string) {
    ::OutputDebugStringA(string);
}
inline void OutputDebugString(const wchar_t* string) {
    ::OutputDebugStringW(string);
}

蛇足

Visual Studio 2017で新規プロジェクト作成してそのままビルドするとエラーになりません?
ついさっき試してみたら、ソースコードが全部BOM無しのUTF-8になっていてコードページが違うとかで怒られました。
リソースはコンパイルは通ったものの文字化けになるし。

なのでソースファイルは上書き保存して「エンコード付で保存」でBOM付にして、リソースファイルは#include "windows.h"の前に#pragma code_page(65001)を追加しました。これでビルドが通るようになり、文字化けもなくなりました。