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. 【译】RAID的概念和RAID对于SQL性能的影响

    简介 我们都听说过RAID,也经常作为SQL DBA.开发人员或构架师在工作中讨论RAID.但是,其实我们很多人都对RAID的原理,等级,以及RAID是如何影响SQL Server性能并不甚了解. 本 ...

  2. python模块、异常

    1. python 模块 模块是一个包含所有你定义的函数和变量的文件,其后缀名是.py.模块可以被别的程序引入,以使用该模块中的函数等功能.这也是使用 python 标准库的方法.(有点像java的c ...

  3. subjective--主观

    existing in the mind; belonging to the thinking subject rather than to the object of thought (oppose ...

  4. 轨迹条(Trackbar)

    1.创建 createTrackbar(轨迹条名称,窗口名称,滑动条的初始位置,滑动条的最大值,回调函数XXX,不懂) 其中回调函数为 void XXX(滑动条的位置,用户数据)在c++中函数名为指向 ...

  5. layout_gravity 属性和 gravity属性的区别

    安卓中  LinearLayout有两个非常相似的属性: android:gravity与android:layout_gravity. 区别在于: android:gravity 属性是对该view ...

  6. 解决老大难疑惑:指针 vs 引用

    ▶疑问描述 1.  引用reference的本质: 常指针 ——> 什么时候用指针?= 就按Java中的引用变量那样用? ——> 什么时候用引用?  ①函数的入参/返回值时   ②T&am ...

  7. Visual Studio的语法着色终于调得赏心悦目

    代码可读性瞬间大大提升.Reshaper真的强大.

  8. C#文件操作之把一个文件复制到另外一个文件夹下

    一.文件复制例子如下,具体情况,根据需求扩展. /// <summary> /// /// </summary> /// <param name="srcFol ...

  9. Json提取器。

  10. JavaWeb第一天--HTML

    HTML HTML简介 HTML(Hyper TextMarkupLanguage) 超文本标记语言. 超文本: 超越了文本仅仅展示信息的功能范畴,泛指:图片.有样式的文字.超链接. 标记: 标签. ...