Windows 窗口的诞生过程:

定义窗口类结构(WNDCLASS) -> 注册窗口类(RegisterClass) -> 创建窗口(CreateWindow) -> 显示窗口(ShowWindow) -> 更新窗口(UpdateWindow) -> 消息循环(GetMessage -> TranslateMessage ->DispatchMessage)

WNDCLASS结构:

Windows 的窗口总是基于窗口类来创建的,窗口类同时确定了处理窗口消息的窗口过程(回调函数)。

结构原型:

typedef struct tagWNDCLASSW {
UINT style; //指定窗口类型,各种“类风格”(详见下方↓)可以使用按位或操作符组合起来
WNDPROC lpfnWndProc; //指定窗口过程(必须是回调函数)
int cbClsExtra; //预留的额外空间,一般为 0
int cbWndExtra; //预留的额外空间,一般为 0
HINSTANCE hInstance; //应用程序的实例句柄
HICON hIcon; //为所有基于该窗口类的窗口设定一个图标
HCURSOR hCursor; //为所有基于该窗口类的窗口设定一个鼠标指针
HBRUSH hbrBackground; //指定窗口背景色
LPCWSTR lpszMenuName; //指定窗口菜单
LPCWSTR lpszClassName; //指定窗口类名
} WNDCLASSW, *PWNDCLASSW, NEAR *NPWNDCLASSW, FAR *LPWNDCLASSW;

在创建应用程序窗口之前,必须调用 RegisterClass 函数来注册窗口类。该函数只需要一个参数,即指向 WNDCLASS 窗口类的指针。因为 WNDCLASS 类包含了窗口所拥有的基本属性。

更多的WNDCLASS结构参考:https://fishc.com.cn/forum.php?mod=viewthread&tid=47123&extra=page%3D1%26filter%3Dtypeid%26typeid%3D420


问题:当一个鼠标键盘按下的时候,之后的过程是怎么样的?

个人理解:

知识点:

1、所有的句柄真正存储在内核区,所以线程,窗口对象其实都是存在内核区的,也就是ring0

2、一个线程对应多个窗口对象,而一个窗口对象只能对应一个线程

过程:

1、当CreateWindow进行窗口创建之后,其中伴随产生了线程对象,线程对象中就会进行存储消息队列

2、当键盘按下之后,操作系统获取了该消息,经过一系列的分析之后会找到对应的窗口对象,并且把该消息封装到了MSG这个结构体中放到该窗口对象的线程对象中的消息队列中

3、GetMessage会把该窗口对象中的线程对象中的消息MSG结构体都取出来

4、MSG会先经过TranslateMessage处理,其作用比如在处理按键的时候,将接收到的十六进制转换为字符码char的时候就可以派上用场了

5、然后再经过DispatchMessageDispatchMessage会拿到当前MSG中对应句柄进去ring0ring0通过MSG中对应的句柄调用对应的窗口回调函数CALLBACK FUNC处理

示例代码:

#include<windows.h>

//全局变量声明
HINSTANCE hinst; //函数声明
int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int);
LRESULT CALLBACK MainWndProc(HWND, UINT, WPARAM, LPARAM); int WINAPI WinMain(HINSTANCE hinstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { //HINSTANCE为应用程序的句柄
WNDCLASSEX wcx; //窗口类
HWND hwnd; //窗口句柄
MSG msg; //消息
BOOL fGotMessage; //是否成功获取消息
hinst = hinstance; //用来保存当前的应用程序的句柄
static TCHAR szAppName[] = TEXT("MyWindows"); //对创建的窗口类进行填充相应的数据结构
wcx.cbSize = sizeof(wcx); //cxSize转到定义为 该类型为UINT
wcx.style = CS_HREDRAW | CS_VREDRAW; //样式 大小改变时 重新进行绘制
wcx.lpfnWndProc = MainWndProc; // 窗口消息处理函数
wcx.cbWndExtra = 0; // 不使用类内存
wcx.cbClsExtra = 0; // 不使用窗口内存
wcx.hInstance = hinstance; //所属的应用程序的实例句柄
wcx.hIcon = LoadIcon(NULL, IDI_APPLICATION); //图标: 默认 指定一个和类相关的图标资源句柄,如果没有指定就用默认的。
wcx.hCursor = LoadCursor(NULL, IDC_ARROW); // 光标:默认
wcx.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); // 画刷背景:WHITE_BRUSH
wcx.lpszMenuName = NULL; // 菜单:无
wcx.lpszClassName = szAppName; // 窗口类的名称
wcx.hIconSm = (HICON)LoadImage(hinstance, //hIconSm指定一个和类相关的小的图标资源句柄,如果是空,系统会根据hIcon的图标来生成一个合适大小的图标来作为和类相关的小的图标资源句柄
MAKEINTRESOURCE(5),
IMAGE_ICON,
GetSystemMetrics(SM_CXSMICON),
GetSystemMetrics(SM_CXSMICON),
LR_DEFAULTCOLOR); if (!RegisterClassEx(&wcx)) { //创建窗口类
return -1;
} //调用CreateWindow API
hwnd = CreateWindow(szAppName, //窗口类名称
TEXT("First Window"), //窗口标题
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, //水平位置:默认
CW_USEDEFAULT, //垂直位置:默认
CW_USEDEFAULT, //宽度位置:默认
CW_USEDEFAULT, //高度位置:默认
(HWND)NULL, // 父窗口:无
(HMENU)NULL, //菜单:使用窗口类的菜单
hinstance, //应用程序实例句柄
(LPVOID)NULL); //窗口创建时数据:无 if (!hwnd) { //创建窗口失败的处理
return -1;
} //显示窗口
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd); //消息循环,作用就是将我们在窗口上产生的msg进行TranslateMessage解析然后再进行DispatchMessage传输给窗口消息处理函数进行处理
while ((fGotMessage = GetMessage(&msg, (HWND)NULL, 0, 0)) != 0 && fGotMessage != -1) {
TranslateMessage(&msg); //翻译作用,比如 在处理按键的时候,将接收到的十六进制转换为字符码char的时候就可以派上用场了
DispatchMessage(&msg); //传输,根据对应的窗口HWND,找到对应的窗口过程函数,比如这里定义的MainWndProc函数进行处理 //当DispatchMessage之后,内核中将该句柄对应的窗口过程函数进行调用
} return msg.wParam;
} /*
MainWndProc
功能:窗口消息处理函数 对所有的消息都使用默认处理函数
*/ LRESULT CALLBACK MainWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { //这里接收的hwnd,uMsg,wParam,lParam
//也就是MSG结构体中的消息,umsg是动作 wParam lParam保存了该动作中的详细信息的,hwnd为该句柄 switch (uMsg) { //switch对产生的消息进行处理
case WM_LBUTTONDOWN:
//MessageBox(NULL, L"hello click", L"hello", MB_OK);
MessageBox(hwnd, L"hello click", L"hello", MB_OK); //如果这里传入的句柄为NULL,那么就能无限产生,我们必须要点击确定才能产生下一个,所以需要获取当前窗口的句
return 0;
case WM_DESTROY: //当进行关闭处理时候 进行ExitThread 结束进程操作
PostQuitMessage(0);
return 0;
case WM_CHAR:
wchar_t szchar[100];
wsprintf(szchar,TEXT("%c\n"), wParam,lParam); //格式化字符串
OutputDebugString(szchar); //调试的时候进行输出格式化的字符串szchar
return 0; default:
return DefWindowProc(hwnd, uMsg, wParam, lParam); //不关心的操作都给windows自己的窗口消息处理函数进行处理
} }

效果图:

学习:窗口创建以及消息处理basic.c的更多相关文章

  1. 深入解析Windows窗口创建和消息分发(三个核心问题:怎么将不同的窗口过程勾到一起,将不同的hwnd消息分发给对应的CWnd类去处理,CWnd如何简单有效的去处理消息,由浅入深,非常清楚) good

    笔记:争取不用看下面的内容,只看自己的笔记,就能记住这个流程,就算明白了: _tWinMain-->AfxWinMain,它调用四个函数: -->AfxWinInit用于做一些框架的初始化 ...

  2. 深入delphi编程理解之消息(一)WINDOWS原生窗口编写及消息处理过程

    通过以sdk方式编制windows窗口程序,对理解windows消息驱动机制和delphi消息编程有很大的帮助. sdk编制windows窗口程序的步骤: 1.对TWndClass对象进行赋值; 2. ...

  3. Linux LVM学习总结——创建卷组VG

    在Linux平台如何创建一个卷组(VG)呢?下面简单介绍一下卷组(VG)的创建步骤.本文实验平台为Red Hat Enterprise Linux Server release 6.6 (Santia ...

  4. 雷林鹏分享:jQuery EasyUI 窗口 - 创建简单窗口

    jQuery EasyUI 窗口 - 创建简单窗口 创建一个窗口(window)非常简单,我们创建一个 DIV 标记: Some Content. 现在运行测试页面,您会看见一个窗口(window)显 ...

  5. 【】opencv窗口创建、大小调整等问题

    opencv窗口创建.大小调整等问题 图像最开始大小可能为1280*720或者其他大小的: 使用cv::resizeWindow函数之后,不同的参数感觉窗口大小没有多少改变,看不出来: 使用cv::s ...

  6. Windows窗口创建的具体步骤

    /*实现窗口创建的六步骤:第一步:创建入口函数WinMain第二步:注册窗口类第三部:实现回调函数的功能第四步:显示窗口第五步:更新窗口第六步:消息循环*/ #include "stdafx ...

  7. IntelliJ IDEA 如何在同一个窗口创建多个项目--超详细教程

    一.IntelliJ IDEA与Eclipse的区别 二.在同一个窗口创建多个项目 1.打开IntelliJ IDEA,点击Create New Project 2.Java Enterprise-- ...

  8. IntelliJ IDEA 如何在同一个窗口创建多个项目

    一.IntelliJ IDEA与Eclipse的区别   二.在同一个窗口创建多个项目 1.打开IntelliJ IDEA,点击Create New Project 2.Java Enterprise ...

  9. AntDesign(React)学习-1 创建环境

    目录: AntDesign(React)学习-15 组件定义.connect.interface AntDesign(React)学习-14 使用UMI提供的antd模板 AntDesign(Reac ...

随机推荐

  1. 【转】Mac入门(一)基本用法

    我前五年一直外包到微软,每天使用的都是Windows系统和.NET. 2012年加入VMware,  公司的工作机是台Mac 笔记本(MacBook Pro), 所以有机会接触Mac系统 Mac和Wi ...

  2. 【搬运工】RHEL6.5 移植使用CentOS 的YUM 步骤

    转载地址:http://www.cnblogs.com/rchen98/p/6056469.html 问题:使用 Red Hat Enterprise Linux Server(RHEL) yum安装 ...

  3. Replication:事务复制 Subscriber的主键列是只读的

    在使用Transactional Replication时,Subscriber 被认为是“Read-Only”的 , All data at the Subscriber is “read-only ...

  4. SpringBoot入门初体验

    概述 Java项目开发中繁多的配置,复杂的部署流程和第三方技术集成让码农在开发项目中效率低下,因此springBoot应运而生. 环境 IntelliJ IDEA 2018.3 jkd1.8 开始(傻 ...

  5. protoc文件生成cs文件

    1.下载protoc工具  点击下载 2.下载解压后打开文件,其中有一个.bat文件,里面对应命令行如下: 编写如下命令行 protoc.exe -I=. --csharp_out=. --grpc_ ...

  6. dotnet core 之 CORS使用示例

    这里列举几个经过验证的可用的CORS使用示例, 方便在需要的时候可以直接使用 示例1 #region snippet2 public void ConfigureServices(IServiceCo ...

  7. H5+asp.net 微信开发 遇到过的坑

    一.微信授权登录 1. 根据code 获取_access_tokens 2. 根据取到的openid和_access_tokens获取用户信息最神奇的是我用我自己的微信账号测试,一开始还可以取到tok ...

  8. Android 8.0的平台上,应用不能对大部分的广播进行静态注册

    引言在Android 8.0的平台上,应用不能对大部分的广播进行静态注册,也就是说,不能在AndroidManifest文件对有些广播进行静态注册,这里必须强调是有些广播,因为有些广播还是能够注册的. ...

  9. Django(一)初始

    一:Web开发中的基本术语 1.两种架构 (1)cs架构 Client/Server:客户端-服务端架构 优点:CS能充分发挥客户端PC的处理能力,很多工作可以在客户端处理后在提交给服务器,用户体验好 ...

  10. 【转】Webpack 快速上手(上)

    嫌啰嗦想直接看最终的配置请戳这里 webpack-workbench (https://github.com/onlymisaky/webpack-workbench) 由于文章篇幅较长,为了更好的阅 ...