WindowClass
单例,负责窗口初始化注册和取消注册;
负责提供静态方法;
放在Window类内部,方便初始化时,wndProc(HandleMsgSetup)
的赋值;
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| class WindowClass { public: static const char* GetName() noexcept; static HINSTANCE GetInstance() noexcept; private: WindowClass() noexcept; ~WindowClass(); WindowClass(const WindowClass&) = delete; WindowClass& operator=(const WindowClass&) = delete; static constexpr const char* wndClassName = "Direct3D Engine Window"; static WindowClass wndClass; HINSTANCE hInst; };
|
Window
1.构造方法
初始化客户区大小和Title;
根据客户区大小计算窗口大小做适应;
注册设备用于捕获消息;
2.析构方法
销毁窗口;
3.回调流程
关键WinApi介绍:
wndProc
必须是静态函数,然后我们窗口类中的消息处理函数时类成员函数,成员函数有个隐藏的参数this指针,所以不可以直接传参给窗口结构体,这里做了一些巧妙的回调;
WM_NCCREATE
: 当首次创建窗口时,在 WM_CREATE
消息之前发送;
Param
: 指向CREATESTRUCT
结构的指针; CREATESTRUCT
的成员与 CreateWindowEx
函数的参数相同;
CREATESTRUCT
中 lpCreateParams
:
包含可用于创建窗口的附加数据;如果由于调用CreateWindow
或CreateWindowEx
函数而创建窗口,则该成员包含函数调用中指定的lpParam
参数的值;
而我们调用CreateWindowEx
时,lpParam
参数填写的正是this指针,也就是window*;
SetWindowLongPtr
: 更改窗口属性;
GetWindowLongPtr
: 获取窗口属性;
GWLP_WNDPROC
: 更改WinProc
的函数指针地址;
GWLP_USERDATA
: 和窗口相关的自定义数据;
执行流程:
1.创建窗口后,消息机制调用HandleMsgSetup
;
2.HandleMsgSetup
通过lParam
参数获得CREATESTRUCTW
结构体指针;
3.通过CREATESTRUCTW
结构体指针获得Window*
指针,也就是当前窗口的实例指针;
4.Window*
通过SetWindowLongPtr
自定义用户数据设置给当前窗口句柄hWnd
;
5.更改WndProc
指向HandleMsgThunk
;
6.通过Window*
指针调用一次成员函数HandleMsg
;
以后每一帧消息机制只会调用HandleMsgThunk
:
7.HandleMsgThunk
中通过GetWindowLongPtr
获取当前窗口的用户自定义数据GWLP_USERDATA
,也就是前面设置的Window*
;
8.通过Window*
调用成员函数HandleMsg
;
9.HandleMsg
中对不同消息拦截处理;
完整代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| class Window { private: class WindowClass { public: static const char* GetName() noexcept; static HINSTANCE GetInstance() noexcept; private: WindowClass() noexcept; ~WindowClass(); WindowClass(const WindowClass&) = delete; WindowClass& operator=(const WindowClass&) = delete; static constexpr const char* wndClassName = "Direct3D Engine Window"; static WindowClass wndClass; HINSTANCE hInst; };
public: Window(int width, int height, const char* name); ~Window(); Window(const Window&) = delete; Window& operator=(const Window&) = delete;
private: static LRESULT CALLBACK HandleMsgSetup(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) noexcept; static LRESULT CALLBACK HandleMsgThunk(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) noexcept; LRESULT HandleMsg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) noexcept;
private: int width; int height; HWND hWnd; };
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
| Window::WindowClass Window::WindowClass::wndClass;
Window::WindowClass::WindowClass() noexcept : hInst(GetModuleHandle(nullptr)) { WNDCLASSEX wc = { 0 }; wc.cbSize = sizeof(wc); wc.style = CS_OWNDC; wc.lpfnWndProc = HandleMsgSetup; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = GetInstance(); wc.hIcon = nullptr; wc.hCursor = nullptr; wc.hbrBackground = nullptr; wc.lpszMenuName = nullptr; wc.lpszClassName = GetName(); wc.hIconSm = nullptr; RegisterClassEx(&wc); }
Window::WindowClass::~WindowClass() { UnregisterClass(wndClassName, GetInstance()); }
const char* Window::WindowClass::GetName() noexcept { return wndClassName; }
HINSTANCE Window::WindowClass::GetInstance() noexcept { return wndClass.hInst; }
Window::Window(int width, int height, const char* name) : width(width), height(height) { RECT wr; wr.left = 100; wr.right = width + wr.left; wr.top = 100; wr.bottom = height + wr.top; AdjustWindowRect(&wr, WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU, FALSE);
hWnd = CreateWindow( WindowClass::GetName(), name, WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU, CW_USEDEFAULT, CW_USEDEFAULT, wr.right - wr.left, wr.bottom - wr.top, nullptr, nullptr, WindowClass::GetInstance(), this );
ShowWindow(hWnd, SW_SHOWDEFAULT); }
Window::~Window() { DestroyWindow(hWnd); }
LRESULT CALLBACK Window::HandleMsgSetup(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) noexcept { if (msg == WM_NCCREATE) { const CREATESTRUCTW* const pCreate = reinterpret_cast<CREATESTRUCTW*>(lParam); Window* const pWnd = static_cast<Window*>(pCreate->lpCreateParams); SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(pWnd)); SetWindowLongPtr(hWnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(&Window::HandleMsgThunk)); return pWnd->HandleMsg(hWnd, msg, wParam, lParam); }
return DefWindowProc(hWnd, msg, wParam, lParam); }
LRESULT CALLBACK Window::HandleMsgThunk(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) noexcept { Window* const pWnd = reinterpret_cast<Window*>(GetWindowLongPtr(hWnd, GWLP_USERDATA));
return pWnd->HandleMsg(hWnd, msg, wParam, lParam); }
LRESULT Window::HandleMsg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) noexcept { switch (msg) { case WM_CLOSE: PostQuitMessage(0); return 0; }
return DefWindowProc(hWnd, msg, wParam, lParam); }
|