Windows编程入门-第一个窗口程序-消息处理

301 阅读6分钟

HelloWorld

打开VS,创建新项目 选择C++ 桌面向导文件 image.png应用程序类型选择桌面应用程序(.exe),勾选空项目,然后单击确定按钮 image.png 在左侧的解决方案资源管理器中,右键单击鼠标,选择源文件,添加,新建项,选择C++文件,命名为HelloWorld.cpp

#include <Windows.h>

int WINAPI WinMain(
	HINSTANCE hInsetance,
	HINSTANCE hPrevInstance,
	LPSTR lpCmdLine,
	int nCmdShow)
{
	MessageBox(NULL, TEXT("Hello World!"),TEXT("12"), MB_OKCANCEL | MB_ICONINFORMATION |
		MB_DEFBUTTON2);
	return 0;
}

image.png 程序的入口函数为WinMain

int WINAPI WinMain(
    HINSTANCE hInsetance,//程序的实例句柄
    HINSTANCE hPrevInstance,//上一个程序的实例句柄
    LPSTR lpCmdLine,//char * arg[] 命令行参数
    int nCmdShow //显示方式 
)

MessageBox语法

int MessageBox(
  [in, optional] HWND    hWnd,
  [in, optional] LPCTSTR lpText,
  [in, optional] LPCTSTR lpCaption,
  [in]           UINT    uType
);

类型:HWND 要创建的消息框的所有者窗口的句柄。 如果此参数为 NULL,则消息框没有所有者窗口。 类型: LPCTSTR 要显示的消息。 如果字符串由多行组成,则可以在每行之间使用回车符和/或换行符分隔行。 类型: LPCTSTR 对话框标题。 如果此参数为 NULL,则默认标题为 Error。 类型: UINT 对话框的内容和行为。 此参数可以是以下标志组的标志的组合。 image.png image.png 更多参数查看learn.microsoft.com/zh-cn/windo…

字符串处理

C++支持两种字符串,常规的ANSI编码(使用""包裹)和Unicode编码(使用L""包裹)

  1. 普通字符串类型CHAR
  2. 宽字符串类型WCHAR 输出用%ls
  3. 通用字符串类型TCHAR 类型未知由环境决定。需要引用tchar.h头文件

微软将这两套字符集及其操作进行了统一,通过条件编译(通过_UNICODE和UNICODE宏)控制实际使用的字符集,这样就有了_T("")这样字符串 字符串常用函数 字符串长度计算:strlen、wcslen、_tcslen 字符串转数字: A版本:atoi、strtol W版本:_wtoi、wcstol T版本:_ttoi、_tcstol 数字到字符串转换: A版本 itoa(不安全)_itoa_s W版本_itow_s T版本_itot_s

演示

#include<Windows.h>
#include<iostream>
#include<tchar.h>

int main()
{
	CHAR char_buff[] = "123456";
	WCHAR wchar_buff[] = L"123456";
	TCHAR tchar_buff[] = _T("123456");
	printf("sizeof char_buff=%d\n", sizeof(char_buff));
	printf("sizeof wchar_buff=%d\n", sizeof(wchar_buff));
	printf("sizeof tchar_buff=%d\n", sizeof(tchar_buff));
	return 0;
}

image.png 通用字符串类型TCHAR 类型未知由环境决定 更改字符集后 image.png

#include<Windows.h>
#include<iostream>
#include<tchar.h>

int main()
{
	CHAR char_buff[] = "123456";
	WCHAR wchar_buff[] = L"12345678";
	TCHAR tchar_buff[] = _T("123456789");
	printf("sizeof char_buff=%d\n", sizeof(char_buff));
	printf("sizeof wchar_buff=%d\n", sizeof(wchar_buff));
	printf("sizeof tchar_buff=%d\n", sizeof(tchar_buff));

	printf("char_buff的长度为:%d\n", strlen(char_buff));
	printf("wchar_buff的长度为:%d\n", wcslen(wchar_buff));
	printf("tchar_buff的长度为:%d\n", _tcslen(tchar_buff));

	return 0;
}

image.png 宽字节字符转换多字符

WideCharToMultiByte()
#define WCHAR_TO_CHAR(lpW_Char,lpChar)
WideCharToMultiByte(CP_ACP,NULL,lpW_Char,-1,lpChar,_countof(lpChar),NULL,FALSE)

多字符转换宽字符

MultiByteToWideChar()
#define CHAR_TO_WCHAR(lpChar,lpWChar)
MultiByteToWideChar(CP_ACP,NULL, lpChar, -1,lpWChar,_countof(lpWChar))

第一个窗口程序

#include<Windows.h>
#include<iostream>

LRESULT CALLBACK WindowProc(
	_In_ HWND hwnd,
	_In_ UINT uMsg,
	_In_ WPARAM wParam,
	_In_ LPARAM lParam
)
{
	switch (uMsg)
	{
	case WM_CREATE:
		MessageBoxW(hwnd, L"窗口创建了", L"提示",MB_OK);
		break;
	case WM_CLOSE:
		MessageBoxW(hwnd, L"窗口关闭了", L"提示", MB_OK);
		DestroyWindow(hwnd);
		PostQuitMessage(0);
		break;
	}
	return DefWindowProcW(hwnd, uMsg, wParam, lParam);
}

int WINAPI WinMain(
	HINSTANCE hInstance,
	HINSTANCE hPreInstance,
	LPSTR lpCmdLine,
	int nCmdShow
)
{
	//1、创建一个窗口类
	WNDCLASSW myClass = { 0 };
	myClass.lpszClassName = L"xiaowang";
	myClass.lpfnWndProc = WindowProc;
	//2、注册窗口类
	RegisterClassW(&myClass);
	//3、创建窗口
	HWND hwindow=CreateWindowW(
		myClass.lpszClassName,
		L"xiaowang",
		WS_OVERLAPPEDWINDOW,
		CW_USEDEFAULT,
		0,
		CW_USEDEFAULT,
		0,
		NULL,
		NULL,
		hInstance,
		0
	);
	//4、显示窗口
	ShowWindow(hwindow,SW_SHOWNORMAL );
	//5、获取消息
	MSG msg = { 0 };
	while (GetMessageW(&msg,0,0,0)) 
	{
		DispatchMessageW(&msg);//分发消息给消息处理函数
	}
	
	return 0;
}

windows程序框架-消息 windows系统是基于消息的操作系统 每一个窗口都在不停的处理消息,所有的操作都是接收到消息之后,进行处理的结果。 围绕着消息的处理,产生了获取消息的消息泵机制也叫消息循环,以及处理消息的窗口回调函数机制。 消息的产生 windows下产生消息的时机共有以下四种:

  1. 用户主动产生的消息
  2. windows系统本身产生的消息
  3. 应用程序本身产生的消息
  4. 其他应用程序产生的消息

应用程序如何接受消息 windows操作系统有一个系统消息队列,每个GUI程序,都有自己的消息队列,系统消息队列负责将消息发送给不同GUI程序的消息队列 API函数: GetMessage 从消息队列中取出消息 DisoatchMessage 将消息发送给消息处理函数

消息处理

Windows通用消息: windows通用消息标志都定义在WINUSER.H中,以WM_开头,大体分为三类。

  1. 窗口消息

例如:WM_CREATE,WM_CLOSE

  1. 命令消息

特指WM_COMMAND消息,与处理用户请求有关,如点击菜单项,工具栏,控件等就会产生命令消息。

  1. 通知消息

特指WM_NOTIFY消息,只使用用windows的公共控件,如列表,视图等 Windows控件消息 控件消息是用于控制控件的一些行为的,不同的控件有不同的控制消息,命名规则如下: BM_按钮控制消息 EM_编辑框控制消息 STM_静态文本控制消息 CM_组合框控制消息 LBM_列表框控制消息 用户自定义消息 除了windows消息外,我们也可以定义自己的消息。系统的消息码在0-WM_USER之间,故我们定义的消息大于WM_USER即可 消息的发送 PostMessage、SendMessage PostMessage会将消息发送到消息队列,应用程序的消息循环会最终得到消息,并分发给回调函数。 SendMessage相当于直接调用窗口的回调函数,等待窗口过程处理结束并返回结果 根据发送消息的方式不同,消息分为两类: 队列消息、非队列消息。

#include<Windows.h>
#include<iostream>

//消息处理函数
void print(LPCWSTR format,...) 
{
    WCHAR wchar_buff[100]{ 0 };
    va_list arglist;
    va_start(arglist, format);
    wvsprintfW(wchar_buff, format, arglist);
    va_end(arglist);
    OutputDebugStringW(wchar_buff);

}
LRESULT CALLBACK WindowProc(
_In_ HWND hwnd,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
)
{
    switch (uMsg)
	{
	case WM_CREATE:
		MessageBoxW(hwnd, L"窗口创建了", L"提示",MB_OK);
		break;
	case WM_CLOSE:
		MessageBoxW(hwnd, L"窗口关闭了", L"提示", MB_OK);
		DestroyWindow(hwnd);
		PostQuitMessage(0);
		break;
    //鼠标移动
	case WM_MOUSEMOVE:
	{
		WORD X = LOWORD(lParam);
		WORD Y = HIWORD(lParam);
		print(L"鼠标移动了!X坐标%d,Y坐标%d\n",X,Y);
		break;
	}
	//鼠标左键
	case WM_LBUTTONDOWN:
		print(L"鼠标左键按下了\n");
		break;
	}
	return DefWindowProcW(hwnd, uMsg, wParam, lParam);
}

int WINAPI WinMain(
	HINSTANCE hInstance,
	HINSTANCE hPreInstance,
	LPSTR lpCmdLine,
	int nCmdShow
)
{
	//1、创建一个窗口类
	WNDCLASSW myClass = { 0 };
	myClass.lpszClassName = L"xiaowang";
	myClass.lpfnWndProc = WindowProc;
	//2、注册窗口类
	RegisterClassW(&myClass);
	//3、创建窗口
	HWND hwindow=CreateWindowW(
		myClass.lpszClassName,
		L"xiaowang",
		WS_OVERLAPPEDWINDOW,
		CW_USEDEFAULT,
		0,
		CW_USEDEFAULT,
		0,
		NULL,
		NULL,
		hInstance,
		0
	);
	//4、显示窗口
	ShowWindow(hwindow,SW_SHOWNORMAL );
	//5、获取消息
	MSG msg = { 0 };
	while (GetMessageW(&msg,0,0,0)) 
	{
		DispatchMessageW(&msg);//分发消息给消息处理函数
	}
	
	return 0;
}

image.png image.png image.png image.png 自定义消息

const UINT WM_USERMSG = WM_USER + 1;
case WM_LBUTTONDOWN:
		print(L"鼠标左键按下了\n");
		SendMessageW(hwnd, WM_USERMSG, 0, 0);
		break;
	case WM_USERMSG:
		print(L"自定义消息\n");
		break;
#include<Windows.h>
#include<iostream>

const UINT WM_USERMSG = WM_USER + 1;

void print(LPCWSTR format,...) 
{
	WCHAR wchar_buff[100]{ 0 };
	va_list arglist;
	va_start(arglist, format);
	wvsprintfW(wchar_buff, format, arglist);
	va_end(arglist);
	OutputDebugStringW(wchar_buff);

}
LRESULT CALLBACK WindowProc(
	_In_ HWND hwnd,
	_In_ UINT uMsg,
	_In_ WPARAM wParam,
	_In_ LPARAM lParam
)
{
	switch (uMsg)
	{
	case WM_CREATE:
		MessageBoxW(hwnd, L"窗口创建了", L"提示",MB_OK);
		break;
	case WM_CLOSE:
		MessageBoxW(hwnd, L"窗口关闭了", L"提示", MB_OK);
		DestroyWindow(hwnd);
		PostQuitMessage(0);
		break;
	case WM_MOUSEMOVE:
	{
		WORD X = LOWORD(lParam);
		WORD Y = HIWORD(lParam);
		print(L"鼠标移动了!X坐标%d,Y坐标%d\n",X,Y);
		break;
	}
	case WM_LBUTTONDOWN:
		print(L"鼠标左键按下了\n");
		SendMessageW(hwnd, WM_USERMSG, 0, 0);
		break;
	case WM_USERMSG:
		print(L"自定义消息\n");
		break;
	}
	return DefWindowProcW(hwnd, uMsg, wParam, lParam);
}

int WINAPI WinMain(
	HINSTANCE hInstance,
	HINSTANCE hPreInstance,
	LPSTR lpCmdLine,
	int nCmdShow
)
{
	//1、创建一个窗口类
	WNDCLASSW myClass = { 0 };
	myClass.lpszClassName = L"xiaowang";
	myClass.lpfnWndProc = WindowProc;
	//2、注册窗口类
	RegisterClassW(&myClass);
	//3、创建窗口
	HWND hwindow=CreateWindowW(
		myClass.lpszClassName,
		L"xiaowang",
		WS_OVERLAPPEDWINDOW,
		CW_USEDEFAULT,
		0,
		CW_USEDEFAULT,
		0,
		NULL,
		NULL,
		hInstance,
		0
	);
	//4、显示窗口
	ShowWindow(hwindow,SW_SHOWNORMAL );
	//5、获取消息
	MSG msg = { 0 };
	while (GetMessageW(&msg,0,0,0)) 
	{
		DispatchMessageW(&msg);//分发消息给消息处理函数
	}
	
	return 0;
}

效果 image.png SendMessageW演示 关闭窗口 打开工具下的spy++ image.png 点击望远镜将准星拖向目标窗口获取句柄 image.png SendMessageW参数1填句柄 参数2填控制消息

case WM_RBUTTONDOWN:
		SendMessageW((HWND)0x00200B2A, WM_CLOSE, 0, 0);
		break;