开启掘金成长之旅!这是我参与「掘金日新计划 · 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);
}