win32api之Windows应用程序(五) 您所在的位置:网站首页 win32api参考手册下载 win32api之Windows应用程序(五)

win32api之Windows应用程序(五)

2023-03-23 21:12| 来源: 网络整理| 查看: 265

什么是消息队列

当我们在使用鼠标或键盘时,操作系统会将这些动作转换为一个消息(message),并将其发送到相应的消息队列中。这个消息包含了一些信息,例如动作的类型、坐标、时间戳等等。

在Windows系统中,每个窗口都有一个消息队列,操作系统将接收到的消息按照先后顺序依次存储在该队列中,等待程序读取和处理

每个线程只有一个消息队列,消息队列是属于线程的,每个线程在创建窗口时才会分配一个消息队列,并不是每个线程都有消息队列。当消息被发送到一个窗口时,系统会将消息放入该窗口所属的线程的消息队列中,线程可以通过GetMessage函数从消息队列中获取消息并进行处理。

有一点要注意:一个窗口只能属于一个线程,但一个线程可以拥有多个窗口

image-20230227162213354

什么是消息处理函数

消息处理函数用于处于各种事件消息的函数,也称为窗口过程函数。当一个窗口收到一个事件消息时,Windows操作系统会调用该窗口的消息处理函数来处理该消息

通常其语法形式如下:

LRESULT CALLBACK WndProc( HWND hWnd, //窗口句柄 UINT message, //消息类型 //wParam和lParam是消息的参数 WPARAM wParam, LPARAM lParam)

当用户进行鼠标点击等操作时,操作系统会将消息发送到应用程序的消息队列中,然后应用程序的消息循环会处理这些消息,例如将其传递给某个特定窗口的消息处理函数

在处理窗口消息时,通常需要检查消息是由哪个窗口发送的,以便正确地响应消息。一个应用程序可以拥有多个窗口,并且每个窗口都有自己的消息处理函数

什么是消息循环

消息循环会不断地从系统队列中获取消息,然后将消息传递给相应的消息处理函数进行处理。在Windows操作系统中,消息循环通常是由函数GetMessage和DispatchMessage进行实现的

以下代码是Visual Studio提供的默认消息函数:

while (GetMessage(&msg, nullptr, 0, 0)) { if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) { TranslateMessage(&msg); //翻译消息 DispatchMessage(&msg); //分发消息 } } 常用API WinMain函数

WinMain是Windows程序的入口函数, WinMain的返回值是一个整数,表示程序的退出状态码。在WinMain函数内部,我们可以创建窗口、初始化程序并执行消息循环等操作

它的语法格式如下:

int WINAPI WinMain( HINSTANCE hInstance, //当前模块的句柄 HINSTANCE hPrevInstance, //废弃,置NULL LPSTR lpCmdLine, //命令行参数,包含应用程序启动时传递的所有命令行参数 int nCmdShow //窗口显示方式,指定应用程序最初如何显示 ); CreateWindow

CreateWindow函数是Windows API中用于创建一个窗口的函数,返回一个HWND类型的窗口句柄,该句柄可以用于操作该窗口,如显示、隐藏、移动、调整大小等

每当使用CreateWindow创建窗口时,操作系统会在内核生成一个窗口对象,该窗口对象包含了窗口的状态信息(如窗口大小, 位置, 标题), 同时也包含了窗口的过程函数指针,用于处理窗口的消息

其语法格式如下:

HWND CreateWindow( LPCWSTR lpClassName, //指定窗口类名 LPCWSTR lpWindowName, //指定窗口标题 DWORD dwStyle, //指定窗口的样式,如是否可见、是否有边框、是否可以调整大小等 //指定窗口的位置和尺寸。 int x, int y, int nWidth, int nHeight, HWND hWndParent, //指定父窗口句柄,若没有父窗口,则为NULL HMENU hMenu, //指定菜单句柄,若没有,则为NULL HINSTANCE hInstance, //指定应用程序实例句柄,即应用程序的模块句柄 LPVOID lpParam //指定窗口创建时传递给消息处理函数的参数 );

以下是常见的dwStyle参数值及其含义:

WS_OVERLAPPEDWINDOW:创建一个拥有各种窗口风格的窗体,包括标题,系统菜单,边框,最小化和最大化按钮等WS_POPUP:创建没有标题栏和边框的弹出式窗口。WS_CHILD:创建一个子窗口。WS_VISIBLE:使窗口可见。WS_DISABLED:禁用窗口和它的子窗口。WS_MINIMIZEBOX:包含最小化按钮。WS_MAXIMIZEBOX:包含最大化按钮。WS_THICKFRAME:包含可调整大小的边框。WS_CAPTION:创建带有标题栏的窗口。WS_SYSMENU:创建带有系统菜单的窗口 ShowWindow

ShowWindow函数用于显示或隐藏指定窗口,如果函数成功,返回值为非零值,否则返回值为零,其语法格式如下:

BOOL ShowWindow( HWND hWnd, //要显示或隐藏的窗口的句柄 int nCmdShow //指定窗口如何显示的常量 );

常用的nCmdShow常量包括:

SW_HIDE:隐藏窗口

SW_SHOW:显示窗口。

SW_SHOWDEFAULT:使用窗口类中定义的默认值显示窗口。

SW_SHOWMAXIMIZED:显示窗口并最大化。

SW_SHOWMINIMIZED:显示窗口并最小化。

GetMessage

GetMessage函数用于从当前线程的消息队列中获取消息。如果当前线程的消息队列为空,即没有任何消息时,GetMessage函数将阻塞当前线程,直到消息队列中有消息为止。GetMessage函数会把获取到的消息复制到由lpMsg参数指向的MSG结构体中。

如果函数检索到了一个消息,则返回非零值;如果函数调用期间发生错误,则返回-1;如果函数检索到了一个WM_QUIT消息,则返回0。

其语法格式如下:

BOOL GetMessage( LPMSG lpMsg, //指向MSG结构体的指针,用于获取消息 HWND hWnd, //窗口句柄,指定窗口消息的范围。若指定为NULL,则获取调用线程的所有消息 UINT wMsgFilterMin, //指定检索的最小消息值。通常设置为 UINT wMsgFilterMax //指定检索的最大消息值。通常设置为0 ); DispatchMessage

DispatchMessage函数是用于分发消息给消息处理函数处理的函数。当GetMessage函数从消息队列中取出一条消息时,就会将这条消息交给DispatchMessage函数来处理,DispatchMessage函数会根据消息的类型和参数,找到对应窗口的消息处理函数

其语法格式如下:

DispatchMessageW( _In_ CONST MSG *lpMsg //指向消息结构体的指针 ); TranslateMessage

TranslateMessage函数用于将键盘或鼠标的输入消息转换成字符消息,具体来说就是将输入的消息转换成WM_CHAR或WM_DEADCHAR消息, 然后交给窗口过程函数处理

其语法格式如下:

TranslateMessage( _In_ CONST MSG *lpMsg //指向消息结构体的指针 ); RegisterClass

RegisterClass函数用于向Windows操作系统注册一个新的窗口类。注册窗口类之后,可以使用CreateWindow函数创建该窗口类的窗口

其语法格式如下:

RegisterClassW( _In_ CONST WNDCLASSW *lpWndClass //指向窗口类结构体的指针 ); 消息类型

以下是常见的Windows消息类型:

WM_CREATE:创建窗口时发送的消息WM_DESTROY:销毁窗口时发送的消息WM_PAINT:绘制窗口内容时发送的消息WM_MOUSEMOVE:鼠标移动时发送的消息WM_LBUTTONDOWN:鼠标左键按下时发送的消息WM_RBUTTONDOWN:鼠标右键按下时发送的消息WM_KEYDOWN:键盘按下时发送的消息WM_COMMAND:当一个控件被点击或选择时发送的消息WM_NOTIFY:控件通知父窗口的消息WM_SIZE:窗口大小改变时发送的消息 简单实例

如下代码是Visual Studio提供的Windows应用程序默认模板

include "framework.h" include "WindowsProject1.h" define MAX_LOADSTRING 100 // 全局变量: HINSTANCE hInst; //当前实例 WCHAR szTitle[MAX_LOADSTRING]; //窗口标题 WCHAR szWindowClass[MAX_LOADSTRING]; //定义窗口类的名称 // 此代码模块中包含的函数的前向声明: ATOM MyRegisterClass(HINSTANCE hInstance); BOOL InitInstance(HINSTANCE, int); LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM); //入口函数 int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow) { //这两行代码表示这两个参数没有使用,避免出现编译器警告 UNREFERENCED_PARAMETER(hPrevInstance); UNREFERENCED_PARAMETER(lpCmdLine); // TODO: 在此处放置代码。 DWORD DLLAdress = (DWORD)hInstance; TCHAR str[255]; wsprintf(str, TEXT("当前模块地址是:%x"),DLLAdress); OutputDebugString(str); //输出内容至VS输出窗口中,便于调试程序时查看 // 初始化全局字符串 LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING); LoadStringW(hInstance, IDC_WINDOWSPROJECT1, szWindowClass, MAX_LOADSTRING); MyRegisterClass(hInstance); // 执行应用程序初始化: if (!InitInstance(hInstance, nCmdShow)) { return FALSE; } MSG msg; //定义消息结构体 HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_WINDOWSPROJECT1)); //加载加速键表 //进入消息循环 while (GetMessage(&msg, nullptr, 0, 0)) { if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) { TranslateMessage(&msg); //翻译消息 DispatchMessage(&msg); //分发消息 } } return (int)msg.wParam; //返回消息参数wParam } // 函数: MyRegisterClass() 目标: 注册窗口类。 ATOM MyRegisterClass(HINSTANCE hInstance) { wcscpy_s(szWindowClass, MAX_LOADSTRING, L"我的第一个窗口程序"); //设置窗口类名 WNDCLASS wndclass = { 0 }; //定义了窗口类的结构体,用于存储窗口类的属性 wndclass.hbrBackground = (HBRUSH)COLOR_BACKGROUND; //指定窗口的背景颜色为默认的背景颜色 wndclass.lpszClassName = szWindowClass; //定义窗口类名 wndclass.hInstance = hInstance; //定义窗口类的实例句柄,此处表示这个窗口类属于当前应用程序实例的 wndclass.lpfnWndProc = WndProc; //定义窗口过程函数(消息处理函数) return RegisterClass(&wndclass); //注册窗口类,之后可以使用CreateWindow函数创建该窗口类的窗口 } // 函数: InitInstance(HINSTANCE, int) // // 目标: 保存实例句柄并创建主窗口 // // 注释: // // 在此函数中,我们在全局变量中保存实例句柄并 // 创建和显示主程序窗口。 // BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) { hInst = hInstance; // 将实例句柄存储在全局变量中 wcscpy_s(szTitle,MAX_LOADSTRING, L"窗口标题"); //设置窗口标题 //创建窗口 HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr); if (!hWnd) { return FALSE; } ShowWindow(hWnd, nCmdShow); //显示窗口 UpdateWindow(hWnd); //更新窗口 return TRUE; } // // 消息处理函数: WndProc(HWND, UINT, WPARAM, LPARAM) // // 目标: 处理主窗口的消息。 // // WM_COMMAND - 处理应用程序菜单 // WM_PAINT - 绘制主窗口 // WM_DESTROY - 发送退出消息并返回 // // //窗口(消息)处理函数 LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_COMMAND: { int wmId = LOWORD(wParam); // 分析菜单选择: switch (wmId) { case IDM_ABOUT: // DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About); break; case IDM_EXIT: DestroyWindow(hWnd); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } } break; case WM_PAINT: { PAINTSTRUCT ps; HDC hdc = BeginPaint(hWnd, &ps); // TODO: 在此处添加使用 hdc 的任何绘图代码... EndPaint(hWnd, &ps); } break; case WM_DESTROY: PostQuitMessage(0); break; default: //默认的窗口处理函数 return DefWindowProc(hWnd, message, wParam, lParam); } return 0; } // “关于”框的消息处理程序。 INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { UNREFERENCED_PARAMETER(lParam); switch (message) { case WM_INITDIALOG: return (INT_PTR)TRUE; case WM_COMMAND: if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) { EndDialog(hDlg, LOWORD(wParam)); return (INT_PTR)TRUE; } break; } return (INT_PTR)FALSE; } 子窗口 什么是子窗口

子窗口是指在一个父窗口中的独立的窗口。子窗口可以是任何标准窗口类,如按钮、编辑框、列表框等,也可以是自定义的窗口类

例如,在一个应用程序的主窗口中,可以创建多个子窗口来显示不同的工具栏、状态栏、文本编辑区等。子窗口的消息处理函数与普通窗口的消息处理函数相同,但需要在创建时指定父窗口句柄

在创建子窗口时使用CreateWindow函数,系统为函数的第一个参数提供了默认值,例如以下代码,第一个参数的值为"BUTTON",即代表当前创建的窗口为编辑框,第二个参数即为编辑框的标题, 第三个参数需设置成WS_CHILD来表示是子窗口,第九个参数表示为控件标识,可以理解成控件的编号(唯一的)

关于控件标识的解释:例如一个窗口有两个按钮, 若要捕捉指定按钮的消息, 可以通过控件标识来进行捕捉

define IDC_BUTTON1 1 CreateWindowA( "BUTTON", "设置", WS_CHILD | WS_VISIBLE, 100, 100, 50, 50, hWnd, (HMENU)IDC_BUTTON1, //控件标识 hInst, NULL, ); 使用实例 LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_COMMAND: { int wmId = LOWORD(wParam); //LOWORD从一个整数中提取其低16位的值 // 分析菜单选择: switch (wmId) { case IDM_ABOUT: DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About); break; case IDM_EXIT: DestroyWindow(hWnd); break; case IDC_BUTTON1: //点击按钮1要执行的代码 MessageBoxA(0, "设置编辑框文本", "提示", 0); SetDlgItemText(hWnd, IDC_EDIT1, L"Hello World"); //设置指定控件的文本内容 break; case IDC_BUTTON2: //点击按钮2要执行的代码 TCHAR EditText[100]; GetDlgItemText(hWnd, IDC_EDIT1, EditText, 100); //获取指定控件的文本内容 MessageBox(0, EditText, L"获取编辑框文本", 0); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } } break; case WM_PAINT: { PAINTSTRUCT ps; HDC hdc = BeginPaint(hWnd, &ps); // TODO: 在此处添加使用 hdc 的任何绘图代码... EndPaint(hWnd, &ps); } break; case WM_DESTROY: PostQuitMessage(0); break; case WM_CREATE: //创建一个编辑框 CreateWindowA( "EDIT", "这是编辑框", WS_CHILD | WS_VISIBLE, 0, 0, 150, 100, hWnd, (HMENU)IDC_EDIT1, hInst, NULL, ); //创建一个按钮1 CreateWindowA( "BUTTON", "设置", WS_CHILD | WS_VISIBLE, 100, 100, 50, 50, hWnd, (HMENU)IDC_BUTTON1, hInst, NULL, ); //创建一个按钮2 CreateWindowA( "BUTTON", "获取", WS_CHILD | WS_VISIBLE, 40, 100, 50, 50, hWnd, (HMENU)IDC_BUTTON2, hInst, NULL, ); break; default: //默认的窗口处理函数 return DefWindowProc(hWnd, message, wParam, lParam); } return 0; }

执行结果如下:

动画



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有