GWLP_USERDATA
昨日せっかくstdcall_thunkを作ったのですが、今回は使わないことにしました。
というのも、ウィンドウクラスは「クラス」であるはずなのに、サンクでインスタンスと結び付けてしまうと、「クラス」でなく「インスタンス」になってしまう気がしたからです。
ウィンドウクラスが「クラス」であることを守ろうとすると、ウィンドウのユーザーデータにインスタンス情報を格納するのが素直な実装だと思います。
この方法にもいろいろ制約があるのですが、今回のように単純な例なら特に問題ないでしょう。
以下、何のひねりもない書きかけコードです。
#include <cstring> #include <stdexcept> #include <windows.h> #include <commctrl.h> class main_window { public: explicit main_window(::HWND handle) : handle_(handle) { } ~main_window() { } private: ::HWND handle_; }; ::LRESULT CALLBACK WindowProc( ::HWND hwnd, ::UINT uMsg, ::WPARAM wParam, ::LPARAM lParam) { try { main_window* pimpl = reinterpret_cast<main_window*>( GetWindowLongPtr(hwnd, GWLP_USERDATA) ); if (uMsg == WM_CREATE) { pimpl = new main_window(hwnd); SetWindowLongPtr( hwnd, GWLP_USERDATA, reinterpret_cast< ::LONG_PTR>(pimpl)); } else if (uMsg == WM_DESTROY) { SetWindowLongPtr(hwnd, GWLP_USERDATA, 0); delete pimpl; ::PostQuitMessage(0); } } catch (const std::exception& e) { ::MessageBoxA(0, e.what(), "Sound Player", MB_OK); } return ::DefWindowProc(hwnd, uMsg, wParam, lParam); } int WINAPI WinMain(::HINSTANCE hInstance, ::HINSTANCE, ::LPSTR, int nCmdShow) { try { { ::INITCOMMONCONTROLSEX data; std::memset(&data, 0, sizeof(data)); data.dwSize = sizeof(data); data.dwICC = ICC_BAR_CLASSES; if (::InitCommonControlsEx(&data) == FALSE) throw std::runtime_error("InitCommonControlsEx() failed"); } ::WNDCLASSEXA wc; std::memset(&wc, 0, sizeof(wc)); wc.cbSize = sizeof(wc); wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = &WindowProc; wc.cbClsExtra = 0; wc.cbWndExtra = sizeof(::LONG_PTR); wc.hInstance = hInstance; wc.hIcon = ::LoadIcon(0, IDI_APPLICATION); wc.hCursor = ::LoadCursor(0, IDC_ARROW); wc.hbrBackground = reinterpret_cast< ::HBRUSH>(::GetStockObject(WHITE_BRUSH)); wc.lpszMenuName = 0; wc.lpszClassName = "MainWindow"; wc.hIconSm = 0; ::ATOM cls = ::RegisterClassExA(&wc); if (cls == 0) throw std::runtime_error("RegisterClassExA() failed"); ::HWND hwnd = ::CreateWindowEx( WS_EX_CLIENTEDGE, MAKEINTATOM(cls), "Sound Player", WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU, CW_USEDEFAULT, CW_USEDEFAULT, 280, 100, 0, 0, hInstance, 0 ); if (hwnd == 0) throw std::runtime_error("CreateWindowEx() failed"); ::ShowWindow(hwnd, nCmdShow); ::UpdateWindow(hwnd); ::MSG msg; while (::GetMessage(&msg, 0, 0, 0)) { ::TranslateMessage(&msg); ::DispatchMessage(&msg); } ::UnregisterClass(MAKEINTATOM(cls), hInstance); return (msg.wParam); } catch (const std::exception& e) { ::MessageBoxA(0, e.what(), "Sound Player", MB_OK); } return 0; }
中途半端ですが、さっきまで熱出してひーひー言ってた割には進んだかなぁと思います。