CPP Windows编程

137 阅读7分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第5天,点击查看活动详情

Windows编程本质就是使用好操作系统,官方文档MSDN。在进行windows编程的时候需要包含一个新的万能头文件,Windows.h

docs.microsoft.com/zh-cn/cpp/c…

developer.aliyun.com/article/300…

常见Windows数据类型

1 常见数据类型

HANDLE是windows编程中最终的一个概念,在计算机中翻译为句柄。用于标识操作系统中的某个对象。

HANDLE 通用句柄

HWND 窗口句柄

HINSTANCE 实例句柄

窗口程序的入口函数为WinMain

int WINAPI WinMain(
    HINSTANCE hInstance,//程序实例句柄
    HINSTANCE hPreInstance,//上一个程序的实例句柄
    LPSTR lpCmdLine,//类似于char* arg[]命令行参数
    int nCmdShow//显示方式
) 
#include<windows.h>

int WINAPI WinMain(
	HINSTANCE hInstance,    //程序实例句柄
	HINSTANCE hPreHinstance,//上一个程序实例句柄,已被弃用
	LPSTR     lpCmdeLine,   //命令行参数类似于之前写main函数中的char** argv
	int       nCmdeShow     //显示方式
) {
	MessageBoxA(0, "Hello World", "title", MB_OK);
	return 0;
}

2 字符串类型

CPP支持两种字符串,即ASCII编码和Unicode编码(L""包裹)

1 普通字符串类型CHAR->char (1个字符占1个字节)

2 宽字符串类型WCHAR->wchar_t 输出用%ls(1个字符占2个字节)

3 通用字符串类型TCHAR->类型位置,有环境觉得。需要引用tchar.h头文件。

微软将这两套字符集及其操作进行了统一,通过条件编译控制实际使用的字符集,这样就有了_T("")这样的字符串。

	CHAR char_buff[] = "123456";
	WCHAR wchar_buff[] = L"123456";
	TCHAR tchar_buff[] = _T("123456");

	printf("char_buff:%d\n", sizeof(char_buff));
	printf("wchar_buff:%d\n", sizeof(wchar_buff));
	printf("tchar_buff:%d\n", sizeof(tchar_buff));
	system("pause");

常见Window API

1 MessageBox

int MessageBox(
    HWND hWnd,
    LPCTSTR lpText,
    LPCTSTR lpCation,
    UINT uType
);

参数

返回值

创建第一个Windows窗口

创建一个Windows窗口分为5步,1,创建一个窗口。2、注册窗口。3、创建窗口句柄(CreateWindowW),4、显示窗口。5、创建回调函数(消息处理机制)

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


LRESULT CALLBACK WindowProc(
	_In_ HWND hwnd, //窗口句柄
	_In_ UINT uMsg, //消息类型
	_In_ WPARAM wParam,
	_In_ LPARAM lParam
);

int WINAPI WinMain(
    HINSTANCE hInstance,
    HINSTANCE hPreInstance,
    LPSTR lpCmdLine,
    int nCmdShow
){
    //1 创建一个窗口类
    WNDCLASSW myClass={0};
    myClass.lpszClassName = L"Dragon";
    myClass.lpfnWndProc = WindowProc;
    //2 注册窗口类
    RegisterClassW(&myClass);
    //3 创建窗口
	HWND hWindow = CreateWindowW(myClass.lpszClassName, L"Dragon", 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 1;

}
//消息处理函数
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);;
}

Windows 程序框架——消息机制

Windows系统是基于消息的操作系统

每一个窗口都在不停的处理消息,所有的操作都是接收到消息之后,进行处理的结果。

围绕着消息的处理,尝试了获取消息的消息泵机制也叫“消息循环”,以及处理消息的窗口回调函数机制

消息的产生

Windows下产生消息的时机共有四种

1 用户主动产生的消息(移动鼠标,输入键盘)

2 Windows系统本身产生的消息。

3 应用程序本身产生的消息。

4 其他应用程序产生的消息。

应用程序如何接收消息?

Windows操作系统有一个系统消息队列,每个GUI程序,都有自己的消息队列,系统消息队列负责将消息发送给不同GUI程序的消息队列。

API函数:

GetMessage 从应用程序消息队列中取出消息

DsipatchMessage 将消息发送给消息处理函数

Windows通用消息

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

1 窗口消息

WM_CREATE、WM_CLOSE、WM_MOUSEMOVE

LRESULT CALLBACK WinProc(
    HWND hWnd, //窗口句柄
    UINT uMsg, //消息类型
    WPARAM wParam //消息带来的参数,根据消息类型的不同参数也不一样
    LPARAM lParam //消息带来的参数,根据消息类型的不同参数也不一样
){
    switch(uMsg){
        case WM_CLOSE:
        DestroyWindow(hWnd);
        PostQuitMessage(0);
        break;
        case WM_MOUSEMOVE:
        WORD LOWORD(lParam)//获取lParam参数的底地址两个字节的值
        WORD HIGORD(lParam)//获取lParam参数的高地址两个字节的值

    }
}
    
    

2 命令消息

特指WM_COMMAND 消息,与处理用户请求有关,如点击菜单项,工具栏,空间等就会尝试命令消息

3 通知消息

特指WM_NOTIFY消息,只使用用windows的公共控件,如列表、视图等

Windows控件消息

控件消息是用于控制控件的一些行为,不同控件有不同的控制消息,命名规则如下:

用户自定义消息

除了windows消息外,我们也可以自定义消息。系统的消息码在0-WM_USER之间,自定的消息大于WM_USER即可。

消息的发送

PostMessage

会将消息发送到消息队列,应用程序的消息循环会最终得到消息,并分发给回调函数。

SendMessage

相当于直接发送给窗口的回调函数(速度更快),等到回调函数处理结束并返回结果

根据发送消息的方式不同,消息分为两类:

队列消息,非队列消息。

LRESULT CALLBACK WinProc(
	HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam
) {
	switch (uMsg) {
	case WM_CREATE:
		MessageBoxW(hWnd, L"DRAGON", L"Title", MB_OK);
		break;
	case WM_CLOSE:
		DestroyWindow(hWnd);
		PostQuitMessage(0);
		break;
	case WM_MOUSEMOVE: {
		WORD x = LOWORD(lParam); // 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);
        SendMessageW((HWND)0xxxxxx,WM_CLOSE,0,0); //关闭0xxxxxx句柄
		break;
	case WM_USERMSG:
		print(L"用户自定义消息\n");
		break;
	}
	return DefWindowProcW(hWnd, uMsg, wParam, lParam);
}

Windows窗口控件

Window控件:

控件是常见的窗口上的交互元素例如:一个按钮,一个复选框,一个列表框等。当控件的特定功能被触发后,会主动发送消息通知父窗口,父窗口可以发送消息给控件控制控件的行为。控件的本质也是一个窗口。

Windows 通用控件:

WC_LISTVIEW 列表框控件

WC_TREEVIEW 树控件

WC_TABCONTROL TAB控件

控件的响应

子控件通知父窗口一些时间,例如子控件被点击,需要通过一下两类消息:

标准控件的消息:WM_COMMAND 通用控件的消息:WM_NOTIFY

	case WM_CREATE:
			CreateWindowW(WC_BUTTON, L"按钮1", WS_CHILD | WS_VISIBLE, 10, 20, 120, 40, hWnd, (HMENU)0x100, hInstance, 0);
			CreateWindowW(WC_BUTTON, L"按钮2", WS_CHILD | WS_VISIBLE, 10, 80, 120, 40, hWnd, (HMENU)0x101, hInstance, 0);
			CreateWindowW(WC_EDITW, L"文本框1", WS_CHILD | WS_VISIBLE|WS_BORDER, 10, 320, 120, 40, hWnd, (HMENU)0x100, hInstance, 0);
			break;
		case WM_COMMAND: {
			WORD ContrlId = LOWORD(wParam);
			switch (ContrlId) {
			case 0x100: {
				MessageBoxW(hWnd, L"按钮1被按下", L"alert", MB_OK);
				break;
			}

			case 0x101: {
				MessageBoxW(hWnd, L"按钮2被按下", L"alert", MB_OK);
				break;
			}

			}
			break;
		}

Windows窗口风格

Windows窗口从其特点主要分为两大类

1 表示窗口和其他窗口关系的包括:WS_OVERLAPED、WS_POPUP 、WS_CHILD

2 表明窗口外观特征,WS_BORDER WS_CAPTION等

常用工具类

输出类

va_list是在C语言中解决变参问题的一组宏,变参问题是指参数的个数不定,可以是传入一个参数也可以是多个;

可变参数中的每个参数的类型可以不同,也可以相同;

可变参数的每个参数并没有实际的名称与之相对应,用起来是很灵活。

va_list表示可变参数列表类型,实际上就是一个char指针fmt。

c语言提供了函数的不定长参数使用,比如 void func(int a, …)。三个省略号,表示了不定长参数。注意:c标准规定了,函数必须至少有一个明确定义的参数,因此,省略号前面必须有至少一个参数。

va_list

宏定义了一个指针类型,这个指针类型指向参数列表中的参数。

void va_start(va_list ap, last_arg)

修改了用va_list申明的指针,比如ap,使这个指针指向了不定长参数列表省略号前的参数。

type va_arg(va_list, type)

获取参数列表的下一个参数,并以type的类型返回。

void va_end(va_list ap)

参数列表访问完以后,参数列表指针与其他指针一样,必须收回,否则出现野指针。一般va_start 和va_end配套使用。

void print(LPCWSTR format, ...)
{
	WCHAR buf[DEBUG_BUF_LEN] = {};
	va_list argList;
	va_start(argList, format);
	wvsprintfW(buf, format, argList);
	va_end(argList);
	OutputDebugStringW(buf);
}