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函数的参数相同;
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中对不同消息拦截处理;
完整代码:
//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);
}
Win32窗口框架的更多相关文章
- 关于Windows窗口框架
		我们知道Windows的窗口消息处理函数是C方式, 面向过程的, 所以窗口框架的基本任务就是将它转成面向对象的方式, 确切的说如何将消息处理函数第一参数HWND转成对象指针. 关于这个问题, 其实网上 ... 
- 第一个手写Win32窗口程序
		第一个手写Win32窗口程序 一 Windows编程基础 1 Win32应用程序的基本类型 1.1 控制台程序 不需要完善的Windows窗口,可以使用DOS窗口 的方式显示. 1.2 Win32窗口 ... 
- SQL Server窗口框架——ROWS、RANGE
		说到窗口框架就不得不提起开窗函数. 开窗函数支持分区.排序和框架三种元素,其语法格式如下: OVER ( [ <PARTITION BY clause> ] [ <ORDER BY ... 
- WIN32窗口程序
		// Win32.cpp : 定义应用程序的入口点. // #include "stdafx.h" #include "Win32.h" void TRACE( ... 
- Win32窗口消息机制 x Android消息机制 x 异步执行
		如果你开发过Win32窗口程序,那么当你看到android代码到处都有的mHandler.sendEmptyMessage和 private final Handler mHandler = new ... 
- 如何在Console下面生成一个WIN32窗口
		一个小挑战? VS2017里面,新建一个控制台工程,输入名字(你不需要也成,有默认的),得到一个控制台工程. 好了,生成的代码,如下: // Win32InConsole.cpp : This fil ... 
- Win32 - 窗口
		Win32 - 窗口 目录 Win32 - 窗口 前言 流程图 创建项目 VS MinGW Win32API字符串 Unicode 和 ANSI 函数 TCHAR WinMain:Win32 Appl ... 
- WIN32 窗口类封装 框架实现部分
		上面已经讲了窗口封装部分,内容可点击:http://www.cnblogs.com/mengdejun/p/4010320.html,下面分享框架部分内容,完成WINDOWS消息迭代 CQFrameW ... 
- WIN32 窗口封装类实现
		CQWnd.h窗口类定义 // QWnd.h: interface for the CQWnd class. // ////////////////////////////////////////// ... 
随机推荐
- Redis3.0.0集群一键脚本  -by古斌
			下载地址(以交由码云托管): https://gitee.com/gubin0412/Redis3.0.0 赋予脚本执行权限 chmod +x redis-gubin.sh 使用 ./redis-g ... 
- BufferedReader 和BufferedWriter
			BufferedWriter: private void test(String content,String destPath) throws IOException { BufferedReade ... 
- mysql基础操作(二):简单查询DQL
			-- 1.查询所有字段 select * from student; -- 2.查询指定的字段 select id from student; select id, name from student ... 
- JDBC中级篇(MYSQL)——在JDBC中如何获得表中的,自增长的字段值
			注意:其中的JdbcUtil是我自定义的连接工具类:代码例子链接: package c_increment; import java.sql.Connection; import java.sql.P ... 
- Faiss使用多线程出现的性能问题
			Faiss使用多线程出现的性能问题 faiss在增加CPU的情况下,反而出现效率低下的问题. 从理论上看,作为一个CPU/GPU计算型的应用,更多的核意味着更大的计算吞吐能力,性能只会越来越好才是. ... 
- jdbc操作mysql(二):封装
			案例四:封装共有操作 封装一个数据库的会话的类 import java.sql.*; public class ConnectionUtil { /** * 获取连接对象的方法,返回一个Connect ... 
- ES6——类表达式
			//类表达式 const Person1 = class{ constructor(){ console.log('aa') } } //也可以跟上类名P,但是变量P在class外部是访问不到的,在c ... 
- 【Qt pro 文件配置】
			一.默认配置 默认的pro文件配置如下: 如果采用Qt默认的pro配置,其编译后产生的文件会默认集中分布在debug和release目录下,如下图的obj和moc等文件对后续打包发布并没有意义. 二. ... 
- Git使用教程三
			2.远程仓库 线上仓库的操作学习以Github为例 2.1完成线上仓库创建 注意:仓库要求在当前账号下唯一 2.2 两种常规使用方式 2.2.1基于http协议 a.创建空目录,名称就称为shop ... 
- Markdown Sublime flowchart.js 流程图
			先亮出来一个 flowchart.js 的 Sample 给 Sublime 安装 MarkdownPreview,这个不必多说了 Sublime Text -> Preferences -&g ... 
