Win32编程-基础

基础

应用程序分类

控制台程序 Console

​ DOS程序,本身没有窗口,通过Windows DOS窗口执行

窗口程序

​ 拥有自己的窗口,可以与用户交互

库程序

​ 存放代码、数据的程序,执行文件可以从中取出代码执行和获取数据

​ 静态库程序:扩展名LIB,在编译链接程序时,将代码放入到执行文件中。

​ 动态库程序:扩展名DLL,在执行文件执行时从中获取代码。

应用程序对比

入口函数

​ 控制台程序 - main

​ 窗口程序 - WinMain

​ 动态库程序 - DllMain

​ 静态库程序 - 无入口函数

文件存在方式

​ 控制台程序、窗口程序 - EXE文件

​ 动态库程序 - DLL文件

​ 静态库程序 - LIB文件

编译工具

编译器CL.EXE 将源代码编译成目标代码.obj

链接器LINK.EXE 将目标代码、库链接生成最终文件

资源编译器RC.EXE (.rc)将资源编译,最终通过链接器存入

最终文件路径 :C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\bin

库和头文件

Windows库

​ kernel32.dll - 提供了核心的API,例如进程、线程、内存管理等

​ user32.dll - 提供了窗口、消息等API

​ gdi32.dll - 绘图相关的API

路径:C:\Windows\System32

头文件

​ windows.h - 所有windows头文件的集合

​ windef.h - windows数据类型

​ winbase.h - kernel32的API

​ wingdi.h - gdi32的API

​ winuser.h - user32的API

​ winnt.h - UNICODE字符集支持

路径: C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Include

相关函数

int WINAPI WinMain(
    HINSTANCE hInstance,//当前程序的实例句柄
    HINSTANCE hPrevInstance, //当前程序前一个实例句柄
    LPSTR lpCmdLine,//命令行参数字符串
    int nCmdShow //窗口的显示方式
);
int MessageBox(
    HWND hWnd,//父窗口句柄
    LPCTSTR lpText, //显示在消息框中的文字
    LPCTSTR lpCaption,  //显示在标题栏中的文字
    UINT uType //消息框中的按钮、图标显示类型
);// 返回点击的按钮ID	

程序编译过程

编译环境准备 
	VCVARS32.BAT
编译程序 - CL
	CL.EXE  –c  xxx.c
链接程序 - LINK
	LINK.EXE xxx.obj xxx.lib 
执行

编写资源的文件 -.rc资源脚本文件

编译rc文件 - RC.EXE

将资源链接到程序中 - LINK.EXE

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mNa6tHpS-1691205905982)(image-20230804165452925.png)]

第一个windows窗口

窗口创建过程

定义WinMain函数
定义窗口处理函数 (自定义,处理消息)
注册窗口类(向操作系统写入一些数据)
创建窗口( 内存中创建窗口 )
显示窗口( 绘制窗口的图像 )
消息循环(获取/翻译/派发消息)
消息处理

代码

#include<windows.h>
//窗口处理函数(自定义,处理消息)
LRESULT CALLBACK WndProc(HWND hWnd, UINT msgID, WPARAM wParam, LPARAM lParam)
{
	return DefWindowProc(hWnd, msgID, wParam, lParam);
}
//入口函数
int CALLBACK WinMain(HINSTANCE hIns, 
	HINSTANCE hPreIns, 
	LPSTR lpCmdLine, 
	int nCmdShow) 
{	
	//注册窗口类
	WNDCLASS wc = { 0 };
	wc.cbClsExtra = 0;
	wc.cbWndExtra = 0;
	wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
	wc.hCursor = NULL;
	wc.hIcon = NULL;
	wc.hInstance = hIns;
	wc.lpfnWndProc = WndProc;
	wc.lpszClassName = "Main";
	wc.lpszMenuName = NULL;
	wc.style = CS_HREDRAW | CS_VREDRAW;
	RegisterClass(&wc);//将以上所有赋值全部写入操作系统
	//在内存创建窗口
	HWND hWnd=CreateWindow("Main", "window", WS_OVERLAPPEDWINDOW, 100, 100, 500, 500, NULL, NULL, hIns, NULL);
	//显示窗口
	ShowWindow(hWnd, SW_SHOW);
	UpdateWindow(hWnd);
	//消息循环
	MSG nMsg = { 0 };
	while (GetMessage(&nMsg, NULL, 0, 0))
	{
		TranslateMessage(&nMsg);
		DispatchMessage(&nMsg);//将消息交给窗口处理函数来处理
	}
	return 0;
}

WINDOWS窗口

注册窗口类

窗口类的概念

窗口类包含了窗口的各种参数信息的数据结构。

每个窗口都具有窗口类,基于窗口类创建窗口。

每个窗口类都具有一个名称,使用前必须注册到系统。

窗口类的分类

系统窗口类

​ 系统已经定义好的窗口类,所有应用程序都可以直接使用。

​ 不需要注册,直接使用窗口类即可。系统已经注册好了。

​ 例如:
​ 按钮 - BUTTON
​ 编辑框 - EDIT

全局及局部窗口类

应用程序全局窗口类
由用户自己定义,当前应用程序所有模块都可以使用。
应用程序局部窗口类
由用户自己定义,当前应用程序中本模块可以使用。

注册窗口类的函数

ATOM RegisterClass( 
		CONST WNDCLASS *lpWndClass //窗口类的数据
	); //注册成功后,返回一个数字标识。

注册窗口类的结构体

typedef struct _WNDCLASS { 
	UINT       style;  //窗口类的风格
    	WNDPROC    lpfnWndProc; //窗口处理函数
    	int        cbClsExtra; //窗口类的附加数据buff的大小
    	int        cbWndExtra; //窗口的附加数据buff的大小
    	HINSTANCE  hInstance; //当前模块的实例句柄
    	HICON      hIcon; //窗口图标句柄
    	HCURSOR    hCursor; //鼠标的句柄
    	HBRUSH     hbrBackground; //绘制窗口背景的画刷句柄
    	LPCTSTR    lpszMenuName; //窗口菜单的资源ID字符串
    	LPCTSTR    lpszClassName; //窗口类的名称
} WNDCLASS, *PWNDCLASS;

style窗口类风格

微软建议不使用全局窗口类

​ 应用程序全局窗口类的注册,需要在窗口类的风格中增加 CS_GLOBALCLASS。
​ 例如:
​ WNDCLASS wce = {0};
​ wce.style = ….|CS_GLOBALCLASS;
​ 应用程序局部窗口类:在注册窗口类时,不添加CS_GLOBALCLASS风格。

​ CS_HREDRAW - 当窗口水平变化时,窗口重新绘制
​ CS_VREDRAW - 当窗口垂直变化时,窗口重新绘制
​ CS_DBLCLKS - 允许窗口接收鼠标双击
​ CS_NOCLOSE - 窗口没有关闭按钮

窗口创建

创建窗口的函数

CreateWindow/CreateWindowEx
	HWND CreateWindowEx(
		DWORD dwExStyle, //窗口的扩展风格
		LPCTSTR lpClassName,  //已经注册的窗口类名称
		LPCTSTR lpWindowName, //窗口标题栏的名字
		DWORD dwStyle, //窗口的基本风格
		int x, //窗口左上角水平坐标位置
		int y, //窗口左上角垂直坐标位置
		int nWidth, //窗口的宽度
		int nHeight,//窗口的高度
		HWND hWndParent,//窗口的父窗口句柄
		HMENU hMenu,//窗口菜单句柄
		HINSTANCE hInstance, //应用程序实例句柄
		LPVOID lpParam //窗口创建时附加参数   
); //创建成功返回窗口句柄

创建窗口的原理

1.系统根据传入的窗口类名称,在应用程序局部窗口类中查找,如果找到执行2,如果未找到执行3。

2.比较局部窗口类与创建窗口时传入的HINSTANCE变量。如果发现相等,创建和注册的窗口类在同一模块,创建窗口返回。如果不相等,继续执行3。

3.在应用程序全局窗口类,如果找到,执行4,如果未找到执行5。

4.使用找到的窗口类的信息,创建窗口返回。

5.在系统窗口类中查找,如果找到创建窗口返回,否则创建窗口失败。此时不需要hInstance句柄。

子窗口的创建

创建时要设置父窗口句柄

创建风格要增加 WS_CHILD|WS_VISIBLE

#include<windows.h>
//窗口处理函数(自定义,处理消息)
LRESULT CALLBACK WndProc(HWND hWnd, UINT msgID, WPARAM wParam, LPARAM lParam)
{
	switch (msgID)
	{
	case WM_DESTROY://关闭窗口返回0
		PostQuitMessage(0);
		break;
	}
	return DefWindowProc(hWnd, msgID, wParam, lParam);
}
//入口函数
int CALLBACK WinMain(HINSTANCE hIns, 
	HINSTANCE hPreIns, 
	LPSTR lpCmdLine, 
	int nCmdShow) 
{	
	//注册窗口类
	WNDCLASS wc = { 0 };
	wc.cbClsExtra = 0;
	wc.cbWndExtra = 0;
	wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
	wc.hCursor = NULL;
	wc.hIcon = NULL;
	wc.hInstance = hIns;
	wc.lpfnWndProc = WndProc;
	wc.lpszClassName = "Main";
	wc.lpszMenuName = NULL;
	wc.style = CS_HREDRAW | CS_VREDRAW;
	RegisterClass(&wc);//将以上所有赋值全部写入操作系统
	//在内存创建窗口
	HWND hWnd=CreateWindowEx(0,"Main", "window", WS_OVERLAPPEDWINDOW, 100, 100, 500, 500, NULL, NULL, hIns, NULL);

	wc.cbClsExtra = 0;
	wc.cbWndExtra = 0;
	wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
	wc.hCursor = NULL;
	wc.hIcon = NULL;
	wc.hInstance = hIns;
	wc.lpfnWndProc = DefWindowProc;
	wc.lpszClassName = "Child";
	wc.lpszMenuName = NULL;
	wc.style = CS_HREDRAW | CS_VREDRAW;
	RegisterClass(&wc);//将以上所有赋值全部写入操作系统
	//创建子窗口
	HWND hChile1 = CreateWindowEx(0, "Child", "c1", WS_CHILD | WS_VISIBLE | WS_OVERLAPPEDWINDOW, 0, 0, 200, 200, hWnd, NULL, hIns, NULL);
	HWND hChile2 = CreateWindowEx(0, "Child", "c2", WS_CHILD | WS_VISIBLE | WS_OVERLAPPEDWINDOW, 200, 0, 200, 200, hWnd, NULL, hIns, NULL);

	//显示窗口
	ShowWindow(hWnd, SW_SHOW);
	UpdateWindow(hWnd);
	//消息循环
	MSG nMsg = { 0 };
	while (GetMessage(&nMsg, NULL, 0, 0))
	{
		TranslateMessage(&nMsg);
		DispatchMessage(&nMsg);//将消息交给窗口处理函数来处理
	}
	return 0;
}

消息基础

消息的概念和作用

消息组成(windows平台下)
窗口句柄
消息ID
消息的两个参数(两个附带信息)
消息产生的时间
消息产生时的鼠标位置
消息的作用
当系统通知窗口工作时,就采用消息的方式派发给窗口。

窗口处理函数

每个窗口都必须具有窗口处理函数。

LRESULT CALLBACK WindowProc(
	    HWND hwnd, //窗口句柄
	    UINT uMsg, //消息ID
	    WPARAM wParam, //消息参数
	    LPARAM lParam  //消息参数
	);

当系统通知窗口时,会调用窗口处理函数,同时将消息ID和消息参数传递给窗口处理函数。在窗口处理函数中,不处理的消息,使用缺省窗口处理函数。例如:DefWindowProc。

消息相关函数

GetMessage - 获取消息。

BOOL GetMessage(
	LPMSG lpMsg, //存放获取到的消息BUFF
	HWND hWnd, //窗口句柄
	UINT wMsgFilterMin,//获取消息的最小ID  
	UINT wMsgFilterMax   //获取消息的最大ID 
);
//lpMsg - 当获取到消息后,将消息的参数存放到MSG结构中。
//hWnd - 获取到hWnd所指定窗口的消息。
//wMsgFilterMin和wMsgFilterMax -只能获取到由它们指定的消息范围内的消息,如果都为0,表示没有范围

TranslateMessage - 翻译消息。将按键消息,翻译成字符消息。

BOOL TranslateMessage(
   	CONST MSG *lpMsg //要翻译的消息地址
   	);

检查消息是否是按键的消息,如果不是按键消息,不做任何处理,继续执行

DispatchMessage - 派发消息

LRESULT DispatchMessage(
    CONST MSG *lpmsg //要派发的消息
);

将消息派发到该消息所属窗口的窗口处理函数上。

常见消息

WM_DESTROY

产生时间:窗口被销毁时的消息。

附带信息:wParam:为0。
lParam : 为0。

一般用法:常用于在窗口被销毁之前,做相应的善后处理,例如资源、内存等。

WM_SYSCOMMAND

产生时间:当点击窗口的最大化、最小化、关闭等。

附带信息:wParam : 具体点击的位置,例如关闭SC_CLOSE等.
lParam : 鼠标光标的位置。
LOWORD(lParam);//水平位置
HIWORD(lParam);//垂直位置

一般用法:常用在窗口关闭时,提示用户处理。

WM_CREATE

产生时间:在窗口创建成功但还未显示时。

附带信息:wParam : 为0。
lParam : 为CREATESTRUCT类型的指针。
通过这个指针可以获取CreatWindowEx中的全部12个参数的信息。

一般用法:常用于初始化窗口的参数、资源等等,包括创建子窗口等。

WM_SIZE

产生时间:在窗口的大小发生变化后。

附带信息:wParam : 窗口大小变化的原因。
lParam : 窗口变化后的大小。
LOWORD(lParam) //变化后的宽度
HIWORD(lParam) //变化后的高度
一般用法:常用于窗口大小变化后,调整窗口内各个部分的布局。

WM_QUIT

产生时间:程序员发送。

附带信息:wParam : PostQuitMessage 函数传递的参数。
lParam : 0。

一般用法:用于结束消息循环,当GetMessage收到这个消息后,会返回FALSE,结束while处理,退出消息循环。

消息循环的原理

消息循环的阻塞

GetMessage - 从系统获取消息,将消息从系统中移除,阻塞函数。当系统无消息时,会等候下一条消息。
PeekMessage - 以查看的方式从系统获取消息,可以不将消息从系统移除,非阻塞函数。当系统无消息时,返回FALSE,继续执行后续代码。

BOOL PeekMessage(
	LPMSG lpMsg,         // message information
	HWND hWnd,           // handle to window
	UINT wMsgFilterMin,  // first message
	UINT wMsgFilterMax,  // last message
	UINT wRemoveMsg //移除标识  
    PM_REMOVE / PM_NOREMOVE//一般是PM_NOREMOVE
);

代码

	//while (GetMessage(&nMsg, NULL, 0, 0))
	//{
	//	TranslateMessage(&nMsg);
	//	DispatchMessage(&nMsg);//将消息交给窗口处理函数来处理
	//}
	while (1)
	{
		if (PeekMessage(&nMsg, NULL, 0, 0, PM_NOREMOVE))
		{//有消息
			if (GetMessage(&nMsg, NULL, 0, 0))
			{
				TranslateMessage(&nMsg);
				DispatchMessage(&nMsg);
			}
			else
			{
				return 0;
			}
		}
		else
		{//空闲处理
			WriteConsole(g_hOutput, "OnIdle", strlen("OnIdle"), NULL, NULL);
		}
	}
发送消息

SendMessage - 发送消息,会等候消息处理的结果。
PostMessage - 投递消息,消息发出后立刻返回,不等候消息执行结果。

BOOL SendMessage/PostMessage(
		HWND hWnd,//消息发送的目的窗口
		UINT Msg, //消息ID
		WPARAM wParam, //消息参数
		LPARAM lParam  //消息参数          
	);
//==PostQuitMessage( 0 );//可以使GetMessage函数返回0
PostMessage(hWnd, WM_QUIT, 0, 0);
//!=SendMessage( hWnd, WM_QUIT, 0, 0);
消息分类

系统消息 - ID范围 0 - 0x03FF
由系统定义好的消息,可以在程序中直接使用。

用户自定义消息 - ID范围 0x0400 - 0x7FFF(31743)
由用户自己定义,满足用户自己的需求。由用户自己发出消息,并响应处理。

​ 自定义消息宏:WM_USER 0x400

总代码

#include<windows.h>
#include<stdio.h>

HANDLE g_hOutput;//接受标准输出句柄

#define WM_MYMESSAGE WM_USER+1001

void OnCreate(HWND hWnd, LPARAM lParam)
{
	CREATESTRUCT* pcs = (CREATESTRUCT*)lParam;
	char* pszText = (char*)pcs->lpCreateParams;
	MessageBox(NULL, pszText, "Info", MB_OK);

	CreateWindowEx(0, "EDIT", "hello", WS_CHILD | WS_VISIBLE | WS_BORDER, 0, 0, 200, 200, hWnd, NULL, 0, NULL);
}
void OnSize(HWND hWdnd, LPARAM lParam)
{
	short nWidth = LOWORD(lParam);
	short nHight = HIWORD(lParam);
	char szText[256] = { 0 };
	sprintf(szText, "WM_SIZE:宽:%d,高:%d\n", nWidth, nHight);
	WriteConsole(g_hOutput, szText, strlen(szText), NULL, NULL);
}
void OnMyMessage(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
	char szText[256] = { 0 };
	sprintf(szText, "自定义消息被处理 wParam=%d,lParam=%d", wParam, lParam);
	MessageBox(hWnd, szText, "Info", MB_OK);
}
//窗口处理函数(自定义,处理消息)
LRESULT CALLBACK WndProc(HWND hWnd, UINT msgID, WPARAM wParam, LPARAM lParam)
{
	switch (msgID)
	{
	case WM_MYMESSAGE:
		OnMyMessage(hWnd, wParam, lParam);
		break;
	case WM_CREATE:
		SendMessage(hWnd, WM_MYMESSAGE, 1, 2);
		OnCreate(hWnd, lParam);
		break;
	case WM_DESTROY://关闭窗口返回0
		//==PostQuitMessage( 0 );//可以使GetMessage函数返回0
		PostMessage(hWnd, WM_QUIT, 0, 0);
		//!=SendMessage( hWnd, WM_QUIT, 0, 0);
		break;
	case WM_SIZE:
		OnSize(hWnd,lParam);
		break;
	case WM_SYSCOMMAND:
		if (wParam == SC_CLOSE)
		{
			int nRet=MessageBox(hWnd, "WM_SYSCOMMAND是否退出", "Infor", MB_YESNO);
			if (nRet == IDYES)
			{
				//什么都不写
			}
			else
			{
				return 0;
			}
		}
		break;
	}
	return DefWindowProc(hWnd, msgID, wParam, lParam);
}
//入口函数
int CALLBACK WinMain(HINSTANCE hIns, 
	HINSTANCE hPreIns, 
	LPSTR lpCmdLine, 
	int nCmdShow) 
{	
	AllocConsole();//增加DOS
	g_hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
	//注册窗口类
	WNDCLASS wc = { 0 };
	wc.cbClsExtra = 0;
	wc.cbWndExtra = 0;
	wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
	wc.hCursor = NULL;
	wc.hIcon = NULL;
	wc.hInstance = hIns;
	wc.lpfnWndProc = WndProc;
	wc.lpszClassName = "Main";
	wc.lpszMenuName = NULL;
	wc.style = CS_HREDRAW | CS_VREDRAW;
	RegisterClass(&wc);//将以上所有赋值全部写入操作系统
	//在内存创建窗口
	char pszText[] = "附加信息";
	HWND hWnd=CreateWindowEx(0,"Main", "window", WS_OVERLAPPEDWINDOW, 100, 100, 500, 500, NULL, NULL, hIns, pszText);

	wc.cbClsExtra = 0;
	wc.cbWndExtra = 0;
	wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
	wc.hCursor = NULL;
	wc.hIcon = NULL;
	wc.hInstance = hIns;
	wc.lpfnWndProc = DefWindowProc;
	wc.lpszClassName = "Child";
	wc.lpszMenuName = NULL;
	wc.style = CS_HREDRAW | CS_VREDRAW;
	RegisterClass(&wc);//将以上所有赋值全部写入操作系统
	//创建子窗口
	//HWND hChile1 = CreateWindowEx(0, "Child", "c1", WS_CHILD | WS_VISIBLE | WS_OVERLAPPEDWINDOW, 0, 0, 200, 200, hWnd, NULL, hIns, NULL);
	//HWND hChile2 = CreateWindowEx(0, "Child", "c2", WS_CHILD | WS_VISIBLE | WS_OVERLAPPEDWINDOW, 200, 0, 200, 200, hWnd, NULL, hIns, NULL);

	//显示窗口
	ShowWindow(hWnd, SW_SHOW);
	UpdateWindow(hWnd);
	//消息循环
	MSG nMsg = { 0 };
	//while (GetMessage(&nMsg, NULL, 0, 0))
	//{
	//	TranslateMessage(&nMsg);
	//	DispatchMessage(&nMsg);//将消息交给窗口处理函数来处理
	//}
	while (1)
	{
		if (PeekMessage(&nMsg, NULL, 0, 0, PM_NOREMOVE))
		{//有消息
			if (GetMessage(&nMsg, NULL, 0, 0))
			{
				TranslateMessage(&nMsg);
				DispatchMessage(&nMsg);
			}
			else
			{
				return 0;
			}
		}
		else
		{//空闲处理
			WriteConsole(g_hOutput, "OnIdle", strlen("OnIdle"), NULL, NULL);
		}
	}
	return 0;
}
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值