【Windows编程】windows窗口创建过程详解

这篇具有很好参考价值的文章主要介绍了【Windows编程】windows窗口创建过程详解。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

搞windows开发,必须熟悉vs自己的开发工具,这会提高你的开发效率;我用的是vs2013;感觉不错;

1 应用程序的分类

在windows平台上大致有一下三类:

win创建一个窗口,Windows编程,windows,microsoft,c++


其中,dos程序本身没有窗口,其实它的意思是:控制台程序自己并不会创建窗口,而DOS窗口仅仅是dos程序本身向OS借过来的一个窗口,也就是说,dos窗口是OS创建的;

窗口程序:自己拥有窗口的意思就是你自己程序本身就是可以创建一个窗口,比如你的QQ界面啥的这样


2 应用程序分类的对比

win创建一个窗口,Windows编程,windows,microsoft,c++


注意:动态库不能虽然有入口函数,但是不能够独立的执行;


3 编译工具

win创建一个窗口,Windows编程,windows,microsoft,c++


其中rc.exe是转呗编译资源文件的,这是在windows独有的,一般我们的窗口资源,图片资源,菜单资源,画饼画刷等资源都是在资源文件中,然后也需要进行编译;最后链接到可执行文件里;

这些编译工具都是可以找到的,在你的开发工具VS的路径中:
我的就在这里,可能你们会有 12.0 是11.0 13.0等不一样的差别,并且我存放在C盘,你们要看开发环境在哪个盘了;

C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\bin

win创建一个窗口,Windows编程,windows,microsoft,c++


4 windows库文件和头文件

windows的源码API是不公开的,只提供动态库让我们去使用,只要我们有windows的库文件头文件就可以使用windowsAPI函数了;
win创建一个窗口,Windows编程,windows,microsoft,c++


win创建一个窗口,Windows编程,windows,microsoft,c++


其实我们开发时候,使用windows.h头文件就可以直接调用windowsAPI,并不需要专门包含其他windef.h winbase.h 。。。。。等头文件;


5 WinMain函数和MessageBox函数初始

win创建一个窗口,Windows编程,windows,microsoft,c++


WinMain函数:windows编程时候的入口函数
hInstance :当前实例句柄,可以理解:可以找到一块内存的变量,找到哪块内存呢?找到你的进程那一块内存;
可能还有朋友理解不了,想一想WinMain函数被调用之前,是不是进程已经形成了?那从时间角度上来说,WinMain函数就可以被传参进程的内存信息了;这完全没有毛病;
第二个参数:被废弃;
第四个参数:就是窗口最大化,最下化,还是正常 显示;


MessageBox函数功能:就是弹出一个提示框;
第一个参数:父窗口句柄,也就是希望你的弹出窗口显示在哪个窗口的中呗;如果填NULL,表示弹出的窗口的父窗口是桌面;
与此同时:HWND是窗口句柄,作用就是找到一块内存,什么内存?就是存放窗口的数据结构的内存;窗口数据结构?是什么?就是你的窗口大小,颜色,背景,菜单等信息组成的数据结构咯;


6 窗口类

win创建一个窗口,Windows编程,windows,microsoft,c++


7 窗口类的分类

win创建一个窗口,Windows编程,windows,microsoft,c++


系统窗口类:OS创建的窗口就是系统窗口类;比如我们的dos窗口,比如我们的桌面;
win创建一个窗口,Windows编程,windows,microsoft,c++


如果你在win32项目中,要使用系统窗口类,直接调用CreateWindows函数就可以创建成功,不需要注册窗口类的步骤;
比如这里创建一个编辑框的窗口类:(连RegisterWindows函数都没有调用)

win创建一个窗口,Windows编程,windows,microsoft,c++


8 注册窗口类函数

win创建一个窗口,Windows编程,windows,microsoft,c++
该函数,失败返回0,可以用来检测是否注册窗口类成功,注册窗口类:说直白就是向OS写入一个变类型为WNDXLASS的结构体变量,并且初始化他而已;

9 注册窗口类的结构体

win创建一个窗口,Windows编程,windows,microsoft,c++


10 注册全局和局部窗口类

win创建一个窗口,Windows编程,windows,microsoft,c++


不建议用全局窗口类,微软官方手册说的;
CS_DBLCLKS:该参数如果没有,那么你的窗口无论点多块的双击都是两次单击;


11 创建窗口的函数

win创建一个窗口,Windows编程,windows,microsoft,c++


后缀有Ex的函数,和没有Ex的函数,区别就是Ex的函数多路第一个参数,但是这个参数没有实际的用途,所以也不必要关心;


先关注,第二个和倒数第二个参数:
第二个参数:表示注册窗口类的名称;
倒数第二个参数:表示该窗口和哪个进程相关联;
win创建一个窗口,Windows编程,windows,microsoft,c++


CreateWindow内部的执行过程:

win创建一个窗口,Windows编程,windows,microsoft,c++


win创建一个窗口,Windows编程,windows,microsoft,c++

一般来说:我们调用CreateWindow都是为了创建局部窗口了类:
大概执行步骤就是拿到传入的窗口类名字去内核查找窗口类名字是否匹配(内核的窗口类,是你提前注册好的);
找到就继续匹配,你传入的instance 局部是否匹配内核的instance, 如果匹配表示你的窗口就是创建在本进程;
成功后返回一个窗口句柄,供你使用;


12 创建一个windows的过程步骤

win创建一个窗口,Windows编程,windows,microsoft,c++


基本基本代码框架:

#include <Windows.h>

LRESULT CALLBACK WndPro(HWND hWnd,UINT msgID,WPARAM wParam,LPARAM lParam)
{
	switch (msgID)
	{
	case WM_DESTROY: //点击关闭按钮
		PostQuitMessage(0); //使得GetMessage返回0
		break;
	default:
		break;
	}
	return DefWindowProc(hWnd,msgID,wParam,lParam);
}
int WINAPI WinMain(HINSTANCE hinstance,HINSTANCE pHinstance,LPSTR lpCmdLine,int nShowLine)
{
	//注册主窗口类
	WNDCLASS wc;
	wc.cbClsExtra = 0;
	wc.cbWndExtra = 0;
	wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
	wc.hCursor = NULL;						//默认光标
	wc.hIcon = NULL;						//默认图标 图标就是标题栏左上角那个东西
	wc.hInstance = hinstance;
	wc.lpfnWndProc = WndPro;				//窗口过程函数
	wc.lpszClassName = "WinBase";			//窗口类名字,随便起也行
	wc.lpszMenuName = NULL;					//无菜单
	wc.style = CS_HREDRAW | CS_VREDRAW;		//窗口垂直水平变化时候,窗口自动重画
	RegisterClass(&wc);						//向OS写入 wc变量


	// 在内存中创建一个窗口
	HWND hWnd = CreateWindow("WinBase", /*窗口的类名*/
		"Windows",						/*窗口标题*/
		WS_OVERLAPPEDWINDOW,			/*窗口样式*/
		100, 100, 100, 100,				/*窗口x,y,width,height*/
		NULL, NULL, hinstance, NULL);	/*父窗口:桌面 菜单:无 窗口是当前进程的 无附加参数*/
	//显示窗口
	ShowWindow(hWnd, SW_SHOW);			//SW_SHOW按原样显示,也就是说Create设置的参数
	//刷新窗口-->就是在此显示一次
	UpdateWindow(hWnd);
	//消息循环
	MSG msg;
	while(GetMessage(&msg, NULL, 0, 0))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	return 0;
}

TranslateMessage(&msg)的大致执行过程,当我们按下大写字母键盘a时候;

win创建一个窗口,Windows编程,windows,microsoft,c++


13 创建一个子窗口的方法

和创建一个Windows一样,只不过,需要一点区别:
首先肯定也要注册一个子窗口类,当然,这个类只要有一个就可以,一个窗口类是可以被创建为多个窗口的;也就是说,我们又一个子窗口类,就可以调用多次CreateWindow来进行创建窗口了;


对于CreateWindows函数。必要设置的参数是:
win创建一个窗口,Windows编程,windows,microsoft,c++


这是创建主窗口,和子窗口的基本框架:

#include <Windows.h>

LRESULT CALLBACK WndPro(HWND hWnd,UINT msgID,WPARAM wParam,LPARAM lParam)
{
	switch (msgID)
	{
	case WM_DESTROY: //点击关闭按钮
		PostQuitMessage(0); //使得GetMessage返回0
		break;
	default:
		break;
	}
	return DefWindowProc(hWnd,msgID,wParam,lParam);
}
int WINAPI WinMain(HINSTANCE hinstance,HINSTANCE pHinstance,LPSTR lpCmdLine,int nShowLine)
{
	//注册主窗口类
	WNDCLASS wc;
	wc.cbClsExtra = 0;
	wc.cbWndExtra = 0;
	wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
	wc.hCursor = NULL;						//默认光标
	wc.hIcon = NULL;						//默认图标 图标就是标题栏左上角那个东西
	wc.hInstance = hinstance;
	wc.lpfnWndProc = WndPro;				//窗口过程函数
	wc.lpszClassName = "WinBase";			//窗口类名字,随便起也行
	wc.lpszMenuName = NULL;					//无菜单
	wc.style = CS_HREDRAW | CS_VREDRAW;		//窗口垂直水平变化时候,窗口自动重画
	RegisterClass(&wc);						//向OS写入 wc变量

	//注册子窗口类
	WNDCLASS wc_child;
	wc_child.cbClsExtra = 0;
	wc_child.cbWndExtra = 0;
	wc_child.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
	wc_child.hCursor = NULL;						//默认光标
	wc_child.hIcon = NULL;						//默认图标 图标就是标题栏左上角那个东西
	wc_child.hInstance = hinstance;
	wc_child.lpfnWndProc = DefWindowProc;				//窗口过程函数
	wc_child.lpszClassName = "Child";			//窗口类名字,随便起也行
	wc_child.lpszMenuName = NULL;					//无菜单
	wc_child.style = CS_HREDRAW | CS_VREDRAW;		//窗口垂直水平变化时候,窗口自动重画
	RegisterClass(&wc_child);


	// 在内存中创建一个窗口
	HWND hWnd = CreateWindow("WinBase", /*窗口的类名*/
		"Windows",						/*窗口标题*/
		WS_OVERLAPPEDWINDOW,			/*窗口样式*/
		100, 100, 100, 100,				/*窗口x,y,width,height*/
		NULL, NULL, hinstance, NULL);	/*父窗口:桌面 菜单:无 窗口是当前进程的 无附加参数*/
	// 创建一个子窗口

	HWND hWnd_child = CreateWindow("Child",
		"child___",
		WS_CHILD | WS_VISIBLE | WS_OVERLAPPEDWINDOW,
		0, 0, 40, 40, hWnd, NULL, hinstance, NULL);

	//显示窗口
	ShowWindow(hWnd, SW_SHOW);			//SW_SHOW按原样显示,也就是说Create设置的参数
	//刷新窗口-->就是在此显示一次
	UpdateWindow(hWnd);
	//消息循环
	MSG msg;
	while(GetMessage(&msg, NULL, 0, 0))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	return 0;
}

重点关注这里:
其他样式方面可以按你的场景进行设计;


win创建一个窗口,Windows编程,windows,microsoft,c++


14 消息的概念及其作用

win创建一个窗口,Windows编程,windows,microsoft,c++


在Windows下的消息,其实就是一个结构体信息而已,里面包含了上面PPT的一些成员,组成了一个消息;
win创建一个窗口,Windows编程,windows,microsoft,c++


注意每个窗口都对应一个窗口处理函数:也就是说,每当你调用一个CreateWindow都会对应一个窗口处理函数;
但是多个窗口是可以复用一个窗口处理函数的;


要理解:消息是你应用程序产生的,然后由你操作系统抓到,并把它放入消息队列,再由GetMessage从中取出消息,交给DispatchMessage函数进行派发给窗口处理函数进行处理(这个过程就是OS拿到你的消息,找到你对应的处理消息的函数,进行处理,这里使用的机制就是回调函数的机制,DispatchMessage内部就是回调了你窗口过程函数);


如DispatchMessage大致的工作流程:
拿到你的消息,就可以拿到你的窗口句柄,又知道每个窗口句柄对应一个窗口处理函数,自然而然,可以找到你的消息对应窗口处理函数进行调用处理消息;
并且你发现,在函数内部调用你的窗口处理函数进行传参的四个参数,也就是说我们MSG结构体的前4个成员变量,所以说,我们只要有了消息,就可以进行消息处理是完全没有问题的;
win创建一个窗口,Windows编程,windows,microsoft,c++


win创建一个窗口,Windows编程,windows,microsoft,c++


所以我们要清楚,当消息产生是要要关注消息是哪个窗口产生的,产生的消息是什么,产生的消息交给谁去处理;


15 浅谈GetMessage 函数

函数:该函数获取本进程消息队列中的消息;
win创建一个窗口,Windows编程,windows,microsoft,c++


第二个参数:指定为NULL,抓取本进程所有窗口的消息,如果为指定句柄,那么他只会抓取该句柄的消息;
返回值:该函数的返回值,只有在GetMessage抓到一个WM_QUIT消息时候,才会返回0;这个消息是PostQuitMessage(0) 函数调用发出的;


16 浅谈 TranslateMessage 函数

win创建一个窗口,Windows编程,windows,microsoft,c++


该函数只会翻译键盘消息,并且翻译可见字符消息,也就是在ASCII表中可见字符,比如字母和数字等;如果不是可见字符的按键消息那么就不会做任何事情;


17 使用消息

在微软中,提供了大概有1000多个消息,我们可以直接拿来用;使用消息时候,需要关注三点:
消息的产生时间;
消息的附带两个参数,告知的信息;
消息的一般用法;


使用消息时候,并不是使用消息的变量去使用,而是使用消息的ID去使用;
也就是说,不是直接去用MSG定义变量使用消息,而是用我们的MSG里面的一个messageID 去使用;


WM_DESTROY 消息:
请注意:这个消息并不是你鼠标点击右上角那个叉叉才产生的,而是窗口被销毁前系统自动把你产生的一个消息哦;
win创建一个窗口,Windows编程,windows,microsoft,c++


WM_SYSCOMMND:
点击菜单框都会产生,包括你的边界滚动条,所以一般这个消息在处理的时候,还要通过WParam参数进行判断你按的位置是哪个地方,比如wParam == SC_CLOSE 表示你按的是 关闭按钮,那么你就可以对其进行处理,假如你按的是其他菜单的其他位置你就可以不处理;
win创建一个窗口,Windows编程,windows,microsoft,c++


win创建一个窗口,Windows编程,windows,microsoft,c++


该消息是自己发送,调用PostQuitMessage发送,并且该消息不用自己处理,让系统处理;


其实消息种类太多,无法一一说明,这里只是举例,需要还是自己查手册啊;


18 消息循环的基本原理

win创建一个窗口,Windows编程,windows,microsoft,c++


GetMessage是个阻塞函数,如果没有抓不到消息,那么就阻塞,如果抓到消息就返回;
阻塞可不是一个好习惯;所以我们经常需要配合非阻塞函数PeekMessage来使用;


对比:阻塞和非阻塞的写法:

// 主消息循环: 阻塞
	while (GetMessage(&msg, NULL, 0, 0))
	{	
			TranslateMessage(&msg);
			DispatchMessage(&msg);
	}
	/****************************************************************/
	/****************************************************************/
	/****************************************************************/
	// 主消息循环: 非阻塞
	while (1)
	{
		if (!PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))
		{
			//没有消息,空闲处理
		}
		else
		{
			//有消息
			if (!GetMessage(&msg, NULL, 0, 0))
			{
				return 0;
			}
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
	}

19 发送消息

我们知道,GetMessage可以从消息队列中抓消息进行处理
win创建一个窗口,Windows编程,windows,microsoft,c++


但是我们并不知道,消息到底是谁发送的;


win创建一个窗口,Windows编程,windows,microsoft,c++


首先得明白,不管是系统发的消息,还是程序员自己手动发的消息,在windows中发送消息,只能由这两个函数进行发送;
SendMessage: 阻塞函数,发送消息,消息没被处理完都不会返回;
PostMessage: 非阻塞函数;
我们自己只需要拿到消息的四个参数信息即可使用该两个函数,但是我们知道消息的信息是有6个成员信息组成,其实该函数内部会自己通过一些方式拿到剩余的两个信息:也就是说消息的坐标,消息的时间;我们不关心这两个消息;
我们要知道,PostMessage函数,发送消息,直接发送到消息队列中的,而SendMessage并不是直接发送消息到消息队列,至于发到哪?后面会讲到;


20 消息的分类

win创建一个窗口,Windows编程,windows,microsoft,c++


自定义消息的基本使用步骤:

win创建一个窗口,Windows编程,windows,microsoft,c++


21 消息队列

win创建一个窗口,Windows编程,windows,microsoft,c++


22 消息队列分类

win创建一个窗口,Windows编程,windows,microsoft,c++
系统的消息队列:保存所有进程产生的消息,该消息队列很大:
消息的产生首先交由给系统的消息队列,再由OS每隔一段时间将消息转发到各个进程的消息队列中;
GetMessage只会抓取本进程的消息;
win创建一个窗口,Windows编程,windows,microsoft,c++


23 消息和消息队列的关系

win创建一个窗口,Windows编程,windows,microsoft,c++


队列消息:消息进队列;
非队列消息:消息不进队列;
win创建一个窗口,Windows编程,windows,microsoft,c++


有些消息必须进队列,如WM_QUIT,因为GetMessage要返回,必须在队列抓到该消息;有些消息必须不进队列,如WM_CREATE,因为该消息,在窗口处理函数之前就会产生;
有些消息可进可不进,如WM_SIZE;


24 GetMessage函数内部执行过程

win创建一个窗口,Windows编程,windows,microsoft,c++

  1. GetMessage 是阻塞函数,GetMessage 只会从进程还是线程中消息队列获取消息;
  2. 该函数若发现消息队列无消息,就会询问系统的消息队列是否有消息;如果有系统就会吧消息刷新到本进程的消息队列中;
  3. 如果本进程消息队列无消息,系统队列无消息,没有绘图消息,没有定时器消息,没有整理资源,释放内存,那么GetMessage就会阻塞;PeekMessage干的事和GetMessage一样,区别就是最后一个步骤他不会阻塞;

WI_PAINT消息:在窗口从0到1被创建前,系统会发送一个消息,且该消息不进消息队列,直接调用窗口处理函数;文章来源地址https://www.toymoban.com/news/detail-786755.html


到了这里,关于【Windows编程】windows窗口创建过程详解的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Windows API编程01-详解第一个程序(超级详细)

    联系WeChat:i-xiaodi,交流,付费课程学习 简单介绍Windows API: Windows API(Application Programming Interface)是Microsoft Windows平台的应用程序编程接口,其主要目的是让应用程序开发人员可以调用操作系统提供的一组例程功能,而无须考虑其底层的源代码实现及内部工作机制。API函数是

    2024年01月21日
    浏览(24)
  • 创建一个基本的win32窗口

    (1)向系统注册一个窗体类 (2)根据窗体类创建窗口 (3)进入消息循环 (1)主函数的输入参数 (2) 窗口类 (3) 回调函数

    2024年02月07日
    浏览(33)
  • Win11/Windows11设置始终以管理员身份运行cmd窗口

    在使用Windows进行开发时,我们经常需要使用管理员身份运行cmd窗口, 但是每次打开都需要右键\\\"以管理员身份运行\\\",比较浪费时间, 下面将介绍在Win11/Windows11系统中,设置始终以管理员身份运行cmd窗口!         在搜索栏输入终端,点击打开。         如下图所示:  

    2024年02月12日
    浏览(40)
  • Flink Windows(窗口)详解

    Windows是流计算的核心。Windows将流分成有限大小的“buckets”,我们可以在其上应用聚合计算( ProcessWindowFunction , ReduceFunction , AggregateFunction 或 FoldFunction )等。在Flink中编写一个窗口计算的基本结构如下: Keyed Windows Non-Keyed Windows In a nutshell, a window is created as soon as the first

    2024年02月10日
    浏览(41)
  • C/C++ 从零实现一个windows窗口(非常详细)

    C/C++教程目录(专栏文章列表,欢迎订阅,持续更新...) https://blog.csdn.net/weixin_50964512/article/details/125710864 学习完C/C++之后,最郁闷的可能就是感觉啥也干不了,怎么才能写出平常我们所使用的软件模样? 而对于大部分人来说,最常使用的就是windows系统,所以这就需要了解w

    2024年02月11日
    浏览(44)
  • python --根据windows窗口名称、进程pid打开窗口(pygetwindow详解)

    简介: pygetwindow 是一个Python库,用于获取、操作和管理当前打开的窗口。它提供了一些常用的窗口操作方法,包括获取窗口句柄,获取窗口位置和大小,移动和调整窗口大小,最小化、最大化和还原窗口,以及模拟输入和焦点控制等。 安装 详解 获取当前所有窗口 获取指定标

    2024年02月07日
    浏览(48)
  • 【Windows】RPC调用过程实例详解

    概述:windows 创建 RPC调用过程实例详解 参考文章:Remote procedure call (RPC)(远程过程调用 (RPC)) - Win32 apps | Microsoft Learn 定义接口的第一步是使用 uuidgen 实用工具生成通用唯一标识符(UUID)。UUID使客户端和服务端能够相互识别。该工具包含在阿庄平台软件开发工具包中(SDK)

    2024年02月07日
    浏览(29)
  • 【Python】实现一个类似于Glass2k的Windows窗口透明化软件

            网上看到一款Windows下的窗口透明化工具Glass2k(Glass2k官网),可以简单地通过快捷键实现任意窗口的透明化,还挺方便的,想用Python自己实现一下类似的功能。          软件已经开源到 :窗口透明化小工具开源地址         效果图如下:         工具包含以

    2024年02月22日
    浏览(24)
  • windows下用Geth创建一个私有链(笔记)

    Geth安装后 在其安装目录下创建一个文件夹privateChain 在privateChain文件夹下创建一个文件genesis.json(这是创世区块的配置文件) 在genesis.json文件中输入配置创世区块的代码(来自:https://geth.ethereum.org/docs/interface/private-network) 初始化 在命令行窗口privateChain目录下,使用如下命

    2024年01月20日
    浏览(24)
  • Windows实现端口转发(附配置过程图文详解)

    利用Windows端口转发,实现本地设备 ⬅➡ 公网主机 ⬅➡ 远端服务器 以 管理员身份 打开“命令提示符”cmd 防火墙必须关闭 这个命令可以查询本机已设置的端口转发规则 端口转发规则包含(本机本地侦听IP192.168.3.6和侦听端口240x)+(远端服务器IP+端口)的对应关系 这个命令

    2024年02月15日
    浏览(25)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包