DirectX学习——Win32窗口框架

Win32窗口框架

WindowClass

单例,负责窗口初始化注册和取消注册;

负责提供静态方法;

放在Window类内部,方便初始化时,wndProc(HandleMsgSetup)的赋值;

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函数的参数相同;

CREATESTRUCTlpCreateParams

包含可用于创建窗口的附加数据;如果由于调用CreateWindowCreateWindowEx函数而创建窗口,则该成员包含函数调用中指定的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中对不同消息拦截处理;

完整代码:

//window.h
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;
};
//window.cpp
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);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小紫苏0

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值