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. // ////////////////////////////////////////// ...
随机推荐
- 映射Map、队列Queue、优先级队列PriorityQueue
映射Map 将对象映射到其他对象的能力是解决编程问题的有效方法.例如,考虑一个程序,它被用来检查 Java 的 Random 类的随机性.理想情况下, Random 会产生完美的数字分布,但为了测试这 ...
- (2)hadoop之-----配置免密码登录
ssh-keygen -t rsa 然后一路回车 在家目录下会生成 .ssh 目录 ls -la 查看 进入 .ssh cd .ssh cp ~/.s ...
- Promise.resolve()与Promise
//Promise.resolve()和Promise.reject()常用来生成已经被决议为失败或者成功的promise案例 //Promise.reject()简单一些,不管传给它什么值,它决议为 ...
- Linux系统的内核编译
<1>给虚拟机分配2048M内存 <2>配置高可用yum源 <3>下载软件 <1>安装内核源码包 根据依赖性提示,安装对应的包 下载并安装软件包(3个) ...
- 机器学习之支持向量机(python)
参考链接:https://blog.csdn.net/weixin_33514582/article/details/113321749.https://blog.csdn.net/weixin_44 ...
- Docker 面试宝典
Docker 是什么? 是实现容器技术的一种工具 是一个开源的应用容器引擎 使用 C/S 架构模式,通过远程API 来管理 可以打包一个应用及依赖包到一个轻量级.可移植的容器中 容器是什么? 对应用软 ...
- VUE001. 拖动div盒子(自定义指令v-directives)
拖动div是一个逻辑很简单的需求,监听容器的鼠标按下松开的事件,执行函数通过DOM改变标签的CSS偏移量. 在VUE构建的项目中,通过标签的 @mousedown 和 @mouseup 赋予行为事件, ...
- NLP与深度学习(四)Transformer模型
1. Transformer模型 在Attention机制被提出后的第3年,2017年又有一篇影响力巨大的论文由Google提出,它就是著名的Attention Is All You Need[1]. ...
- 最全Windows版本jemalloc库(5.2.1)及其使用:包含动态库和静态库、x86版本和x64版本、debug版本和release版本
编写服务器程序时,需要频繁的申请和释放内存,长时间运行会产生大量的内存碎片,这就导致即使当前系统中的闲置内存还足够多,但也无法申请到大的连续可用的内存块,因为此时的物理内存已经千疮百孔像个马蜂窝.此外 ...
- 作业帮-PHP技术一面整理
项目经验介绍 RPC 调用的协议 用amf 和 base64编码 我想问的是通信协议:调用rpc接口时的过程是什么样?比如业务调用PHP接口的时候,用的是什么协议? (没理解)(https://www ...