C++(底层窗口实现)

本文详细介绍了Windows程序设计的基础,包括SDK和API、窗口与句柄的概念,以及消息队列和消息处理。重点讲解了窗口过程函数在事件驱动编程中的角色,如何响应键盘和鼠标消息。此外,还展示了创建和管理窗口的典型代码流程,从WinMain函数到窗口过程的实现。
摘要由CSDN通过智能技术生成

win32

Windows消息机制

1.SDK和API

SDK:
软件开发工具包 (Software Development Kit) ,一般都是一些被软件工程师用于为特定的软件包、软件框架、硬件平台、操作系统等建立应用软件的开发工具的集合。

API函数:
Windows 操作系统提供给应用程序编程的接口(Application Programming Interface)。Windows应用程序API函数是通过C语言实现的,所有主要的Wi ndows函数都在Windows. h头文件中进行了声明。Windows 操作系统提供了1000多种API函数。

2.窗口和句柄

窗口是Windows应用程序中一个非常重要的元素,一个Windows 应用程序至少要有一个窗口,称为主窗口。
窗口是屏幕上的一块矩形区域,是Windows应用程序与用户进行交互的接口。利用窗口可以接收用户的输入、以及显示输出。
一个应用程序窗口通常都包含标题栏、菜单栏、系统菜单、最小化框、最大化框、可调边框,有的还有滚动条。如下图:
应用程序窗口
窗口可以分为客户区和非客户区,如上图。客户区是窗口的一部分,应用程序通常在客户区中显示文字或者绘制图形。

标题栏、菜单栏、系统菜单、 最小化框和最大化框、可调边框统称为窗口的非客户区,它们由Windows系统来管理,而应用程序则主要管理客户区的外观及操作。

窗口可以有一个父窗口,有父窗口的窗口称为子窗口。除了上图所示类型的窗口外,对话框和消息框也是一-种窗口。在对话框上通常还包含许多子窗口,这些子窗口的形式有按钮、单选按钮、复选框、组框、文本编辑框等。

在Windows应用程序中,窗口是通过窗口句柄( HIND)来标识的。我们要对某个窗口进行操作,首先就要 得到这个窗口的句柄。

句柄( HANDLE)是Windows程序中一个重要的概念,使用也非常频繁。在Windows程序中,有各种各样的资源 (窗口、图标、光标,画刷等),系统在创建这些资源时 会为它们分配内存,并返回标识这些资源的标识号,即句柄。 在后面的内容中我们还会看到图标句柄( HICON)、 光标句柄( HCURSOR)和画刷句柄( HBRUSH) 。

3.消息与消息队列

Windows程序设计是一种完全 不同于传统的DOS方式的程序设计方法。它是一种事件驱动方式的程序设计模式,主要是基于消息的。
每一个Windows应用程序开始执行后,系统都会为该程序创建一个消息队列,这个消息队列用来存放该程序创建的窗口的消息。

例如,当用户在窗口中画图的时候,按下鼠标左键,此时,操作系统会感知到这一事件, 于是将这个事件包装成一一个消息,投递到应用程序的消息队列中,等待应用程序的处理。

然后应用程序通过一个消息循环不断地从消息队列中取出消息,并进行响应。

在这个处理过程中,操作系统也会给应用程序“发送消息”。所谓“发送消息”,实际上是操作系统调用程序中一个专门负责处理消
息的函数,这个函数称为窗口过程。
在这里插入图片描述

4.WinMain函数

当Windows 操作系统启动一个程序时,它调用的就是该程序的WinMain函数(实际是由插入到可执行文件中的启动代码调用的)。WinMain是Windows 程序的入口点函数,与DOS程序的入口点函数main的作用相同,当WinMain函数结束或返回时,Windows 应用程序结束。

Windows 编程模型

一个完整的Win32程序(#include <windows.h>),该程序实现的功能是创建-一个窗口,并在该窗口中响应键盘及鼠标消息,程序的实现步骤为:

  1. winMain函数的定义
  2. 创建一个窗口
  3. 进行消息循环
  4. 编写窗口过程函数
  5. 通过循环取消息
  6. 处理消息(窗口过程)

代码如下:

 #include <windows.h>//底层实现窗口的头文件



//6.处理消息(窗口过程)这是最后一步,但是把它写到了上面,起始是从程序入口函数开始

//CALLBACK 代表__stdcall:参数的传递顺序:从右至左依次入栈,并且在函数返回前清空堆栈
LRESULT CALLBACK WindowProc(
	HWND hwnd,  //消息所属的窗口句柄
	UINT uMsg,  //具体的消息名称  WM_xxxx消息名
	WPARAM wParam,//键盘附加消息
	LPARAM lParam//鼠标附加消息
	
	)

{
	//switch根据不同的消息做不同的处理
	switch (uMsg)
	{
	case WM_CLOSE:
		//所有xxxxWindow为结尾的方法,都不会进入消息队列中,而是直接执行
		DestroyWindow(hwnd);  //DestroyWindow发送另一个消息 WM_DESTROY
		break;

	case WM_DESTROY:
		PostQuitMessage(0); //发送正常的退出
		break;

	case WM_LBUTTONDOWN://鼠标左键按下

		{

		
		int xPos = LOWORD(lParam);//Xposition,x位置,打印鼠标位置
		int yPos = HIWORD(lParam);

		char buf[1024];//定义一个字符数组
		wsprintf(buf,TEXT("X=%d,Y=%d"),xPos,yPos);//拼接字符串1.buf你要把字符串拼接到哪里,2.你要拼接的字符串具体信息

		MessageBox(hwnd,buf,TEXT("鼠标左键按下"),MB_OK);

		break;
	}
	case WM_KEYDOWN://键盘按下

		MessageBox(hwnd,TEXT("键盘按下"),TEXT("键盘按下"),MB_OK);

		break;
	case WM_PAINT://绘图
		
		PAINTSTRUCT ps;//绘图结构体
		HDC hdc = BeginPaint(hwnd,&ps);

		TextOut(hdc,100,100,TEXT("hello"),strlen("hello"));

		EndPaint(hwnd,&ps);
		break;

	}

	//返回值用默认处理方式
	return DefWindowProc(hwnd,uMsg,wParam,lParam);
}



//程序入口函数

//WINAPI宏 代表__stdcall:参数的传递顺序:从右至左依次入栈,并且在函数返回前清空堆栈

int WINAPI WinMain( 
	HINSTANCE hInstance,  //应用程序实例句柄
	HINSTANCE hPrevInstance,//上一个应用程序句柄,在win32环境下参数一般为null,不起作用了
	LPSTR lpCmdLine,   //char*argv[]
	int nShowCmd )//显示命令  最大化、最小化、正常
{
	//1.设计窗口
	//2.注册窗口
	//3.创建窗口
	//4.显示和更新
	//5.通过循环取消息
	//6.处理消息(窗口过程)


	//1.设计窗口
	WNDCLASS wc;  //WNDCLASS窗口的类
	wc.cbClsExtra = 0; //类的额外的内存
	wc.cbWndExtra = 0; //窗口的额外的内存
	wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);//设置背景GetStockObject()是个API  
	wc.hCursor = LoadCursor(NULL,IDC_HAND);//设置光标  第一个是null代表使用系统提供的光标,
	wc.hIcon = LoadIcon(NULL,IDI_ERROR);//图标
	wc.hInstance = hInstance;  //应用程序的实例句柄,传入winmain中的形参即可
	wc.lpfnWndProc = WindowProc; //窗口过程函数,即回调函数,回调函数名可随意更改
	wc.lpszClassName = TEXT("WIN");//指定窗口类名称
	wc.lpszMenuName = NULL;//菜单名称
	wc.style = 0;//显示风格,0代表默认风格


	//2.注册窗口类
	RegisterClass(&wc);//带地址wc


	//3.创建窗口
	/*
	lpClassName,  //类名
	lpWindowName,  标题名
	dwStyle,   风格
	x,         坐标
	y,
	nWidth, 
	nHeight,
	hWndParent,//父窗口
	hMenu,//菜单
	hInstance, //实例句柄
	lpParam   //附加值  鼠标的附加值
	*/
	HWND hwnd = CreateWindow(
		wc.lpszClassName,
		TEXT("WINDOWS"),
		WS_OVERLAPPEDWINDOW,  //混合风格
		CW_USEDEFAULT,    //坐标默认值
		CW_USEDEFAULT,
		CW_USEDEFAULT,
		CW_USEDEFAULT,
		NULL,
		NULL,
		hInstance,
		NULL
		);


	//4.显示和更新
	ShowWindow(hwnd,SW_SHOWNORMAL);//SW_SHOWNORMAL 正常方式展示窗口
	UpdateWindow(hwnd);

	//5.通过循环取消息

	/*
	HWND        hwnd;主窗口句柄,代表哪一个窗口传过来的消息
	UINT        message;具体的消息名称
	WPARAM      wParam;附加消息 键盘消息
	LPARAM      lParam;附加消息 鼠标消息 左右键
	DWORD       time;消息产生的时间
	POINT       pt;附加消息 鼠标消息 点击返回该点坐标点信息
	*/
	MSG msg;//每个消息都是一个结构体

	while (1)
	{
		/*
		__out LPMSG lpMsg,封装好的消息,带lp表示指针,所以要在前面加&
		__in_opt HWND hWnd,  捕获窗口  填NULL代表捕获所有的窗口
		__in UINT wMsgFilterMin,  //最小和最大的过滤的消息 一般填0,代表捕获所有消息
		__in UINT wMsgFilterMax);
		*/


		if (GetMessage(&msg,NULL,0,0)==FALSE)
		{
			break;//退出消息
		}
		
		//翻译消息(比如组合键,就需要获取到消息,翻译消息,再排队,再获取,再分发)
		TranslateMessage(&msg);

		//不为false,分发消息
		DispatchMessage(&msg);

	}

	//6.处理消息(窗口过程)



	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值