WTL、とくにメッセージクラッカー<atlcrack.h>はATLなしの単独でも使えないだろうかと思い、試してみました。結論から言うと可能でした。ただし、2つ理由で少し残念な感じでした。
- 先頭に#define __ATLAPP_H__というおまじないを必要とする。
- END_MSG_MAPを自分で定義する必要がある。
コードはこんな感じです。
#define _WIN32_WINNT 0x0501 #define OEMRESOURCE #define _WTL_NO_AUTOMATIC_NAMESPACE #include <system_error> #include <SDKDDKVer.h> #include <windows.h> #include <windowsx.h> #define __ATLAPP_H__ #include <atlcrack.h> #define END_MSG_MAP() } return FALSE; } #include <tchar.h> class WindowBase { public: static void InitApplication(HINSTANCE hinst) { WNDCLASSEX wcex = { sizeof wcex, CS_HREDRAW | CS_VREDRAW, WndProcEntry, 0, 0, hinst, static_cast<HICON>(LoadImage( nullptr, MAKEINTRESOURCE(OIC_SAMPLE), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_SHARED)), static_cast<HCURSOR>( LoadImage(nullptr, MAKEINTRESOURCE(OCR_NORMAL), IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE | LR_SHARED)), reinterpret_cast<HBRUSH>(COLOR_WINDOW + 1), nullptr, TEXT("WindowBase Class"), nullptr, }; windowClass = RegisterClassEx(&wcex); if (!windowClass) { throw std::system_error( static_cast<int>(GetLastError()), std::system_category()); } } WindowBase() : hwnd() {} void InitInstance() { hwnd = CreateWindowEx( WS_EX_APPWINDOW | WS_EX_OVERLAPPEDWINDOW, MAKEINTATOM(windowClass), TEXT(""), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, nullptr, nullptr, nullptr, this); if (!hwnd) { throw std::system_error( static_cast<int>(GetLastError()), std::system_category()); } } HWND GetWindow() { return hwnd; } protected: virtual BOOL ProcessWindowMessage( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT& lResult, DWORD dwMsgMapID = 0) = 0; private: static BOOL OnNCCreate(HWND hwnd, CREATESTRUCT const* pcs) { SetWindowLongPtr( hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(pcs->lpCreateParams)); return TRUE; } static LRESULT CALLBACK WndProcEntry( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) { HANDLE_MSG(hwnd, WM_NCCREATE, OnNCCreate); } if (auto pwnd = reinterpret_cast<WindowBase*>(GetWindowLongPtr(hwnd, GWLP_USERDATA))) { LRESULT lr = 0; if (pwnd->ProcessWindowMessage(hwnd, msg, wParam, lParam, lr)) { return lr; } } return DefWindowProc(hwnd, msg, wParam, lParam); } static ATOM windowClass; HWND hwnd; //WindowBase(WindowBase const&) = delete; //WindowBase& operator=(WindowBase const&) = delete; WindowBase(WindowBase const&); WindowBase& operator=(WindowBase const&); }; class TestWindow : public WindowBase { public: TestWindow() { } private: void OnDestroy() { PostQuitMessage(0); } void OnPaint(HDC) { ValidateRect(GetWindow(), nullptr); } BEGIN_MSG_MAP_EX(TestWindow) MSG_WM_PAINT(OnPaint) MSG_WM_DESTROY(OnDestroy) END_MSG_MAP() private: TestWindow(TestWindow const&); TestWindow& operator=(TestWindow const&); }; ATOM WindowBase::windowClass; int WINAPI _tWinMain(HINSTANCE hinst, HINSTANCE, LPTSTR, int cmdShow) { try { WindowBase::InitApplication(hinst); TestWindow wnd; wnd.InitInstance(); ShowWindow(wnd.GetWindow(), cmdShow); UpdateWindow(wnd.GetWindow()); for (;;) { MSG msg = {}; auto ret = GetMessage(&msg, nullptr, 0, 0); if (ret == 0 || ret == -1) { return ret; } TranslateMessage(&msg); DispatchMessage(&msg); } } catch (std::exception const& e) { OutputDebugStringA(e.what()); return 1; } } |
ウィンドウプロシージャで非静的メンバ関数を呼び出す処理は自前で作っています。staticメンバ関数のWndProcEntryからBEGIN_MSG_MAP_EX内部で定義されるProcessWindowMessageを呼び出します。WM_NCCREATEでC++オブジェクト (this)とウィンドウを結びつけているので、ATLほど完璧ではありません。
なお、メッセージループもWTL::CMessageLoopを使用できないかと試してみましたが、ATLASSERTなど様々なATLのマクロに依存しているので諦めました。やればできるかもしれませんが無用と判断しました。
これなら、<windowsx.h>のメッセージクラッカーをC++クラスに組み合わせるのとほとんど変わらない(参照:メッセージクラッカー with C++))というのが試してみた感想です。
スポンサード リンク |