1 #pragma once 2 3 namespace windows_user { 4 5 EXTERN_C IMAGE_DOS_HEADER __ImageBase; GetCurrentInstance()6 inline HINSTANCE GetCurrentInstance(){ return ((HINSTANCE)&__ImageBase); } 7 8 template<typename Type> 9 LRESULT CALLBACK WindowCallback(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) noexcept; 10 11 template<typename Type> 12 class window_class 13 { 14 public: Name()15 static LPCWSTR Name() { 16 return Type::class_name(); 17 } 18 Register()19 static ATOM Register() { 20 WNDCLASSEX wcex = {}; 21 wcex.cbSize = sizeof(WNDCLASSEX); 22 23 // defaults that can be overriden 24 wcex.style = CS_HREDRAW | CS_VREDRAW; 25 wcex.hInstance = GetCurrentInstance(); 26 wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); 27 wcex.style = 0; 28 wcex.hIcon = NULL; 29 wcex.hCursor = LoadCursor(NULL, IDC_ARROW); 30 wcex.lpszMenuName = NULL; 31 32 Type::change_class(wcex); 33 34 // not overridable 35 wcex.lpszClassName = Name(); 36 wcex.lpfnWndProc = WindowCallback<Type>; 37 38 return RegisterClassEx(&wcex); 39 } 40 41 private: 42 ~window_class(); 43 window_class(); 44 window_class(window_class&); 45 window_class& operator=(window_class&); 46 }; 47 48 namespace detail { 49 template<typename Type> find(HWND hwnd)50 std::unique_ptr<Type> find(HWND hwnd) { 51 return std::unique_ptr<Type>(reinterpret_cast<Type*>(GetWindowLongPtr(hwnd, GWLP_USERDATA))); 52 } 53 erase(HWND hwnd)54 void erase(HWND hwnd) { 55 SetWindowLongPtr(hwnd, GWLP_USERDATA, 0); 56 } 57 58 template<typename Type> insert(HWND hwnd,std::unique_ptr<Type> type)59 std::unique_ptr<Type> insert(HWND hwnd, std::unique_ptr<Type> type) { 60 if (!type) { 61 return nullptr; 62 } 63 64 SetLastError(0); 65 66 ON_UNWIND(unwind_userdata, [&](){erase(hwnd);}); 67 auto result = SetWindowLongPtr(hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(type.get())); 68 69 LONG winerror = !result ? GetLastError() : ERROR_SUCCESS; 70 71 if (!!winerror || !!result) { 72 return nullptr; 73 } 74 75 unwind_userdata.dismiss(); 76 return type; 77 } 78 } 79 80 template<typename Type> WindowCallback(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)81 LRESULT CALLBACK WindowCallback(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) noexcept { 82 auto type = detail::find<Type>(hWnd); 83 // don't delete type 84 ON_UNWIND(unwind_type, [&](){type.release();}); 85 86 if (message == WM_NCCREATE) { 87 if (type) { 88 // the slot where we would store our type instance is full. abort. 89 return FALSE; 90 } 91 auto cs = reinterpret_cast<LPCREATESTRUCT>(lParam); 92 auto param = reinterpret_cast<Type::param_type*>(cs->lpCreateParams); 93 type = detail::insert(hWnd, std::unique_ptr<Type>(new (std::nothrow) Type(hWnd, cs, param))); 94 if (!type) { 95 return FALSE; 96 } 97 } 98 99 LRESULT lResult = 0; 100 bool handled = false; 101 102 if (type) { 103 std::tie(handled, lResult) = type->message(hWnd, message, wParam, lParam); 104 } 105 106 if (!handled) { 107 lResult = DefWindowProc(hWnd, message, wParam, lParam); 108 } 109 110 if (message == WM_NCDESTROY) { 111 detail::erase(hWnd); 112 // let type destruct 113 unwind_type.dismiss(); 114 } 115 116 return lResult; 117 } 118 } 119