学习:窗口创建以及消息处理basic.c
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、然后再经过DispatchMessage
,DispatchMessage
会拿到当前MSG
中对应句柄进去ring0
,ring0
通过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的更多相关文章
- 深入解析Windows窗口创建和消息分发(三个核心问题:怎么将不同的窗口过程勾到一起,将不同的hwnd消息分发给对应的CWnd类去处理,CWnd如何简单有效的去处理消息,由浅入深,非常清楚) good
笔记:争取不用看下面的内容,只看自己的笔记,就能记住这个流程,就算明白了: _tWinMain-->AfxWinMain,它调用四个函数: -->AfxWinInit用于做一些框架的初始化 ...
- 深入delphi编程理解之消息(一)WINDOWS原生窗口编写及消息处理过程
通过以sdk方式编制windows窗口程序,对理解windows消息驱动机制和delphi消息编程有很大的帮助. sdk编制windows窗口程序的步骤: 1.对TWndClass对象进行赋值; 2. ...
- Linux LVM学习总结——创建卷组VG
在Linux平台如何创建一个卷组(VG)呢?下面简单介绍一下卷组(VG)的创建步骤.本文实验平台为Red Hat Enterprise Linux Server release 6.6 (Santia ...
- 雷林鹏分享:jQuery EasyUI 窗口 - 创建简单窗口
jQuery EasyUI 窗口 - 创建简单窗口 创建一个窗口(window)非常简单,我们创建一个 DIV 标记: Some Content. 现在运行测试页面,您会看见一个窗口(window)显 ...
- 【】opencv窗口创建、大小调整等问题
opencv窗口创建.大小调整等问题 图像最开始大小可能为1280*720或者其他大小的: 使用cv::resizeWindow函数之后,不同的参数感觉窗口大小没有多少改变,看不出来: 使用cv::s ...
- Windows窗口创建的具体步骤
/*实现窗口创建的六步骤:第一步:创建入口函数WinMain第二步:注册窗口类第三部:实现回调函数的功能第四步:显示窗口第五步:更新窗口第六步:消息循环*/ #include "stdafx ...
- IntelliJ IDEA 如何在同一个窗口创建多个项目--超详细教程
一.IntelliJ IDEA与Eclipse的区别 二.在同一个窗口创建多个项目 1.打开IntelliJ IDEA,点击Create New Project 2.Java Enterprise-- ...
- IntelliJ IDEA 如何在同一个窗口创建多个项目
一.IntelliJ IDEA与Eclipse的区别 二.在同一个窗口创建多个项目 1.打开IntelliJ IDEA,点击Create New Project 2.Java Enterprise ...
- AntDesign(React)学习-1 创建环境
目录: AntDesign(React)学习-15 组件定义.connect.interface AntDesign(React)学习-14 使用UMI提供的antd模板 AntDesign(Reac ...
随机推荐
- ElasticSearch中的JVM性能调优
ElasticSearch中的JVM性能调优 前一段时间被人问了个问题:在使用ES的过程中有没有做过什么JVM调优措施? 在我搭建ES集群过程中,参照important-settings官方文档来的, ...
- Java随堂笔记一
今天开始了Java的正式复习,因为有两三年没有接触Java了,所以打算开始从头复习. 下面使课堂的一些随堂笔记,如果有遗忘,我可以随时翻阅该博客. public static void main(St ...
- Channel概述
前言 前两篇文章介绍了NIO核心部分部分之一的缓冲区的相关内容,接下来我们继续学习NIO中另一个重要的核心部分--Channel(通道). 在学习这篇文章之前,先做下简单的说明,本文是一篇关于通道的概 ...
- qbittorrent搜索插件合集
qbittorrent搜索 qbittorrent搜索一个很有特色的功能: 这里收集整理了一些公开网站的插件(Plugins for Public sites),并连 源py文件一起分享. qbitt ...
- Java 8 in Action
https://www.cnblogs.com/HelloDeveloper/p/11404523.html /** * @param args */public static void main(S ...
- 原生JS实现前端动画框架
封装了一个JS方法,可支持块元素的常规动画:高.宽.透明度.位置等,同时支持链式动画和同时运动,参照imooc整理,具体代码如下: /** * 获取HTML元素属性值 * obj是Element, a ...
- 86.使用webpack爬过的坑
Webpack 4 和单页应用入门 https://github.com/wallstreetcn/webpack-and-spa-guide
- Mac安装Java的JDK并进行环境配置
一.下载JDK 1.直接进入oracle官网下载页: https://www.oracle.com/technetwork/java/javase/downloads/index.html 2.选择版 ...
- Java JDBC 操作二进制数据、日期时间
二进制数据 mysql提供了四种类型来存储二进制数据: TinyBlob 最多可存储255字节 Blob 最多可存储65KB MediumBlob 最多可存储16MB LongBlob ...
- 排序算法的c++实现——计数排序
任何比较排序算法的时间复杂度的上限为O(NlogN), 不存在比o(nlgN)更少的比较排序算法.如果想要在时间复杂度上超过O(NlogN)的时间复杂度,肯定需要加入其它条件.计数排序就加入了限制条件 ...