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);
}

Win32窗口框架的更多相关文章

  1. 关于Windows窗口框架

    我们知道Windows的窗口消息处理函数是C方式, 面向过程的, 所以窗口框架的基本任务就是将它转成面向对象的方式, 确切的说如何将消息处理函数第一参数HWND转成对象指针. 关于这个问题, 其实网上 ...

  2. 第一个手写Win32窗口程序

    第一个手写Win32窗口程序 一 Windows编程基础 1 Win32应用程序的基本类型 1.1 控制台程序 不需要完善的Windows窗口,可以使用DOS窗口 的方式显示. 1.2 Win32窗口 ...

  3. SQL Server窗口框架——ROWS、RANGE

    说到窗口框架就不得不提起开窗函数. 开窗函数支持分区.排序和框架三种元素,其语法格式如下: OVER ( [ <PARTITION BY clause> ] [ <ORDER BY ...

  4. WIN32窗口程序

    // Win32.cpp : 定义应用程序的入口点. // #include "stdafx.h" #include "Win32.h" void TRACE( ...

  5. Win32窗口消息机制 x Android消息机制 x 异步执行

    如果你开发过Win32窗口程序,那么当你看到android代码到处都有的mHandler.sendEmptyMessage和 private final Handler mHandler = new ...

  6. 如何在Console下面生成一个WIN32窗口

    一个小挑战? VS2017里面,新建一个控制台工程,输入名字(你不需要也成,有默认的),得到一个控制台工程. 好了,生成的代码,如下: // Win32InConsole.cpp : This fil ...

  7. Win32 - 窗口

    Win32 - 窗口 目录 Win32 - 窗口 前言 流程图 创建项目 VS MinGW Win32API字符串 Unicode 和 ANSI 函数 TCHAR WinMain:Win32 Appl ...

  8. WIN32 窗口类封装 框架实现部分

    上面已经讲了窗口封装部分,内容可点击:http://www.cnblogs.com/mengdejun/p/4010320.html,下面分享框架部分内容,完成WINDOWS消息迭代 CQFrameW ...

  9. WIN32 窗口封装类实现

    CQWnd.h窗口类定义 // QWnd.h: interface for the CQWnd class. // ////////////////////////////////////////// ...

随机推荐

  1. Mybatis中多表联查,查询出来的字段出现重名,造成数据异常的解决方法!

    在做一对多出现的问题,引发的思考:当数据库表中,主表的主键id和明细表的中的字段名相同时怎么办?Mybatis进行自动映射赋值的时候会不会出现异常?                      注意:M ...

  2. WIN10 64bit + QT5.10.0(MinGW3.5.0) + OpenCV3.4.1 无痛安装、配置

    安装QT和配置MinGW 官方下载qt-opensource-windows-x86-5.10.0.exe 正常步骤安装QT5.10.0,安装过程选择自带的MinGW3.5.0编译器即可. 打开QtC ...

  3. 10个最酷的Linux单行命令

    下面是来自  Commandlinefu 网站由用户投票决出的 10 个最酷的 Linux 单行命令,希望对你有用. sudo !! 以 root 帐户执行上一条命令. python -m Simpl ...

  4. LeetCode《买卖股票的最佳时机》系列题目,最详解

    目录 说在前面 引例:只能交易一次 一.动态数组定义 二.状态转移方程 三.初始化 四.优化 无限制买卖 一.动态数组定义 二.状态转移方程 三.初始化 四.优化 交易 2 次,最大利润? 一.动态数 ...

  5. C#多线程开发-线程基础 01

    最近由于工作的需要,一直在使用C#的多线程进行开发,其中也遇到了很多问题,但也都解决了.后来发觉自己对于线程的知识和运用不是很熟悉,所以将利用几篇文章来系统性的学习汇总下C#中的多线程开发. 线程基础 ...

  6. Spring源码浅析之bean实例的创建过程(二)

    在上一篇内容中,介绍了doGetBean方法的源码内容,知道了bean在创建的过程中,有三个范围,单例.多例.Scope,里面都使用到了createBean.下面本篇文章的主要内容,就是围绕creat ...

  7. 菜鸟入门Linux之路(方法论浅谈)

    Linux是为人熟知的OS之王,已"统治"世界.要想学好绝非易事. 作为菜鸟,可以与Linux亲密接触的方法很多,如视频.书籍.各种企培资料等等,如今的在线教育也如火如荼. 总结说 ...

  8. Python - 进度条库 tqdm

    前言 在写生成器的时候,网上看到一个进度条库,感觉蛮有意思,记录下 这个库感觉只有在调试的时候会用到,不做深入学习 内置库,不需要安装 示例代码 from tqdm import tqdm for i ...

  9. JUnit5快速入门指南-2

    重复测试中容易产生的问题 //结果类 private static int result = 0; public static int count(int x) throws InterruptedE ...

  10. weblogic漏洞分析之CVE-2017-10271

    weblogic漏洞分析之CVE-2017-10271 一.环境搭建 1)配置docker 这里使用vulhub的环境:CVE-2017-10271 编辑docker-compose.yml文件,加入 ...