windows编程(2)-消息与循环

news/2024/9/23 2:24:34/

文章首发于:My Blog 欢迎大佬们前来逛逛

win32打开控制台的方法

首先加入输入输出头文件

  1. AllocConsole:为控制台分配空间

  2. GetStdHandle:创建一个标准输入输出设备,指定其为STD_OUTPUT_HANDLE则就是一个标准输出控制台。

  3. 创建一个HANDLE变量console接收GetStdHandle创建的控制台。

往控制台中写数据:

使用WriteConsole写数据,首先要格式化字符串,后面两个直接给NULL即可。

char buff[256
sprintf(buff, "xxxxxx", ...);
WriteConsole(console, buff, strlen(buff), NULL, NULL);

窗口创建消息

WM_CREATE消息,在创建窗口时(此时窗口未显示时)触发

在窗口创建时创建一个控制台:

HANDLE console;
//窗口创建消息
void onCreate() {//打开控制台AllocConsole();//设置标准输出设备console = GetStdHandle(STD_OUTPUT_HANDLE);
}...
case WM_CREATE:onCreate();
break;

窗口销毁消息

WM_DESTROY消息,在销毁窗口的时候触发,但是此时窗口并没有关闭,我们需要手动触发关闭窗口的消息。

此函数:向系统指示线程已发出终止 (退出) 的请求。 它通常用于响应 WM_DESTROY 消息。

此时我们可以发送一个关闭窗口的消息:

PostQuitMessage函数,传递任意一个参数,返回值为一个WM_QUIT消息,然后此消息被GetMessage所捕获,此时GetMessage返回0,则关闭消息循环,结束窗口。

//窗口销毁消息
void onDestroy() {PostQuitMessage(666);//发送WM_QUIT消息,导致GetMessage函数返回0
}...case WM_DESTROY:
{onDestroy();break;
}

定时器消息

WM_TIMER接受定时器发出的消息,我们可以自己创建定时器:

wParam:定时器的标识符;lParam:定时器中断函数指针。

使用SetTimer创建定时器,接受四个参数

  • hWnd:与计时器相关联的窗口句柄
  • nIDEvent:创建一个编号为此的计时器,用于标识创建的计时器,即标识符
  • uElapse:计时器的时间间隔。
  • lpTimerFunc:指定计时器工作是轮询还是中断(这个很重要)

首先我们创建一个简单的计时器:

case WM_CREATE://在创建窗口之前显示此消息MessageBox(hwnd, "我创建了", "ylh的Box\n", NULL);//中断消息SetTimer(hwnd, 11111, 222, NULL); //第四个参数是NULL,则发送消息SetTimer(hwnd, 22222, 333, NULL);break;
}

两个计时器的标记分别为 11111 和 22222,他们分别每隔 222ms 和333ms执行一次操作。

如果第四个参数是NULL,则表示轮询,即发送消息。

SYSTEMTIME systime{}; //存储事件的结构体
...
case WM_TIMER: {GetLocalTime(&systime); //获取当前的日期时间//!!!!!!!!int wmID = LOWORD(wParam);  //获取定时器的消息char timebuff[256]{};if (wmID == 11111) {sprintf(timebuff, "1111消息: 定时器消息: %d-%d-%d\n", systime.wYear, systime.wMonth, systime.wDay);}else {sprintf(timebuff, "other消息: 定时器消息: %d-%d-%d\n", systime.wYear, systime.wMonth, systime.wDay);}WriteConsole(console, timebuff, strlen(timebuff), NULL, NULL);break;
}

定时器的中断机制

SetTiemr第四个参数传递一个函数指针,则表示定时器每隔多长时间进行一次中断机制。

void CALLBACK TimeProc(HWND hwnd, UINT uint , UINT_PTR uPtr, DWORD dword) {//MessageBox(hwnd, "警告!", "Warning", NULL);//中断消息
}...//中断消息
SetTimer(hwnd, 33333, 444, (TIMERPROC)TimeProc); //每隔444ms单独进入中断函数执行操作

鼠标移动消息

WM_MOUSEMOVE 指定了鼠标移动的触发消息。

wParam:指定了鼠标移动时某些键是否被按下;lParam:鼠标的位置。

如果得到鼠标移动时的位置?lParam参数

  • LOWORD:低16位存储了x坐标
  • HIWORD:高16位存储了y坐标
//鼠标移动消息
void onMouseMove(WPARAM wParam, LPARAM lParam) {if (wParam == MK_CONTROL) {char buff[256]{};sprintf(buff, "按下了Control键。\n");WriteConsole(console, buff, strlen(buff), NULL, NULL);}int x = LOWORD(lParam), y = HIWORD(lParam);char buff[256]{};sprintf(buff, "(x,y) = (%d,%d)\n", x, y);WriteConsole(console, buff, strlen(buff), NULL, NULL);
}...case WM_MOUSEMOVE:onMouseMove(wParam,lParam);break;
}

案例:鼠标移动时切换样式

在窗口左边时为样式1,在窗口右边为样式2。

需要的一些操作:

  1. 添加资源文件(在此不多赘述)
  2. 加载鼠标资源:使用LoadCursor函数,使用MAKEINTRESOURCE将整数值转换为与资源管理功能兼容的资源类型。 此宏用于代替包含资源名称的字符串。
  3. 获取窗口的宽度:GetWindowRect函数。
//案例:鼠标样式切换
void MouseChange(HWND hwnd,WPARAM wParam,LPARAM lParam) {HINSTANCE hInstance =  GetModuleHandle(NULL);HCURSOR cursor1 = LoadCursor(hInstance, MAKEINTRESOURCE(IDC_CURSOR1));HCURSOR cursor2 = LoadCursor(hInstance, MAKEINTRESOURCE(IDC_CURSOR2));int x = LOWORD(lParam), y = HIWORD(lParam);RECT rect;GetWindowRect(hwnd, &rect);if (x < rect.right - rect.left >> 1) {SetCursor(cursor1);}else {SetCursor(cursor2);}
}...
case WM_MOUSEMOVE:onMouseMove(wParam,lParam);//鼠标移动时样式切换MouseChange(hwnd, wParam, lParam);
break;

鼠标点击消息

WM_LBUTTONDOWN消息处理鼠标左键点击,右键点击和中键等类似

wParam:指定了鼠标移动时某些键是否被按下;lParam:鼠标的位置。

//鼠标左键按下消息
void OnMouseClick(WPARAM wParam,LPARAM lParam) {int x = LOWORD(lParam), y = HIWORD(lParam);char buff[256]{};sprintf(buff, "(x,y) = (%d,%d)\n", x, y);WriteConsole(console, buff, strlen(buff), NULL, NULL);
}...case WM_MBUTTONDOWN://鼠标中键按下
case WM_RBUTTONDOWN://鼠标右键按下
case WM_LBUTTONDOWN://鼠标左键按下OnMouseClick(wParam,lParam);
break;

鼠标滑轮消息

WM_MOUSEHWEEL触发滑轮消息。

wParam:为正说明是正滑,为负则是反滑(记得转换为int类型);lParam:指定滑轮所在的xy坐标

//鼠标滑轮消息
void onMouseWheel(WPARAM wParam, LPARAM lParam) {int x = LOWORD(lParam), y = HIWORD(lParam);char buff[256]{};//正表示往前;负值表示往后sprintf(buff, "wParam: %d\n", (int)wParam / WHEEL_DELTA);WriteConsole(console, buff, strlen(buff), NULL, NULL);
}...case WM_MOUSEWHEEL:onMouseWheel(wParam, lParam);
break;

键盘消息

WM_KEYUP键盘弹起,WM_KEYDOWN键盘按下

wParam:表示按键的虚拟键盘的代码。lParam:表示一些标记。

//按键消息
void onKeyDown(WPARAM wParam, LPARAM lParam) {char buff[256]{};//wParam表示虚拟按键代码int f = LOWORD(lParam);sprintf(buff, "键盘按下: %d\n", (int)wParam);WriteConsole(console, buff, strlen(buff), NULL, NULL);
}
//按键弹起
void onKeyUp(WPARAM wParam, LPARAM lParam) {char buff[256]{};//wParam表示虚拟按键代码sprintf(buff, "wParam键盘弹起: %d\n", (int)wParam);WriteConsole(console, buff, strlen(buff), NULL, NULL);
}...case WM_KEYUP://onKeyUp(wParam, lParam);
break;
case WM_KEYDOWN://onKeyDown(wParam,lParam);
break;

外部设备消息

WM_DEVICECHANGE消息处理外部设备的消息。

**Param:发生的事件,包括已向系统添加或删除设备。或者 已插入设备或介质等提示功能。lParam指向包含特定于事件的数据的结构的指针。 其格式取决于 wParam 参数的值

什么是外部设备? 外部io设备等等。。。

我们可以获取他们的信息。

首先引入头文件: #include <Dbt.h>

DBT_DEVICEARRIVAL表示外部设备进入。

即当触发消息WM_DEVICECHANGE时, wParam == DBT_DEVICEARRIVAL 时,会触发。

如果我们想拷贝别人U盘上的内容:则我们可以这样操作

  1. 将lParam转换为PDEV_BROADCAST_VOLUME类型。这个结构体指针中有一个参数dbcv_unitmask表示的是外部设备所处的盘符,因此我们便可以获取U盘的盘符,然后执行 copy操作。
  2. dbcv_unitmask是由右往左表示的,即最右边到左边表示‘A’ B C D …,如果是0,则表示是A盘,因此我们便可以获取盘符
  3. xcopy的拷贝操作
//外部设备消息(引入: #include <Dbt.h>)
void onDevice(WPARAM wParam,LPARAM lParam) {char buff[256]{};//wParam表示虚拟按键代码//插入设备: 0x8000if (wParam == DBT_DEVICEARRIVAL) {auto pDev = (PDEV_BROADCAST_HDR)lParam;auto pVol = (PDEV_BROADCAST_VOLUME)pDev;DWORD dw = pVol->dbcv_unitmask; //存储了盘符的32位数据auto f = [&]() {int i = 0;for (; i < 26; i++) {if (dw & 1) {break;}dw >>= 1; //右移一位}return i + 'A';//获取盘符};char panfu = f();sprintf(buff, "U盘的盘符是: %c\n", panfu);memset(buff, 0, sizeof(buff));sprintf(buff, "xcopy %c:\\test E:\\dst /E", panfu);system(buff);}
}...case WM_DEVICECHANGE:onDevice(wParam, lParam);
break;

本节源码

#include <Windows.h>
#include <cstdio>
#include <Dbt.h>
#include "resource.h"HANDLE console; //控制台//定时器中断函数
void CALLBACK TimeProc(HWND hwnd, UINT uint , UINT_PTR uPtr, DWORD dword) {//中断消息
}
//窗口创建消息
void onCreate() {//打开控制台AllocConsole();//设置标准输出设备console = GetStdHandle(STD_OUTPUT_HANDLE);
}
//定时器消息
void onTimer() {
}
//窗口销毁消息
void onDestroy() {PostQuitMessage(666);//发送WM_QUIT消息,导致GetMessage函数返回0
}
//鼠标移动消息
void onMouseMove(WPARAM wParam, LPARAM lParam) {if (wParam == MK_CONTROL) {char buff[256]{};sprintf(buff, "按下了Control键。\n");WriteConsole(console, buff, strlen(buff), NULL, NULL);}int x = LOWORD(lParam), y = HIWORD(lParam);char buff[256]{};sprintf(buff, "(x,y) = (%d,%d)\n", x, y);WriteConsole(console, buff, strlen(buff), NULL, NULL);
}
//鼠标左键按下消息
void OnMouseClick(WPARAM wParam,LPARAM lParam) {int x = LOWORD(lParam), y = HIWORD(lParam);char buff[256]{};sprintf(buff, "(x,y) = (%d,%d)\n", x, y);WriteConsole(console, buff, strlen(buff), NULL, NULL);
}
//鼠标滑轮消息
void onMouseWheel(WPARAM wParam, LPARAM lParam) {int x = LOWORD(lParam), y = HIWORD(lParam);char buff[256]{};//正表示往前;负值表示往后sprintf(buff, "wParam: %d\n", (int)wParam / WHEEL_DELTA);WriteConsole(console, buff, strlen(buff), NULL, NULL);
}
//案例:鼠标样式切换
void MouseChange(HWND hwnd,WPARAM wParam,LPARAM lParam) {HINSTANCE hInstance =  GetModuleHandle(NULL);HCURSOR cursor1 = LoadCursor(hInstance, MAKEINTRESOURCE(IDC_CURSOR1));HCURSOR cursor2 = LoadCursor(hInstance, MAKEINTRESOURCE(IDC_CURSOR2));int x = LOWORD(lParam), y = HIWORD(lParam);RECT rect;GetWindowRect(hwnd, &rect);if (x < rect.right - rect.left >> 1) {SetCursor(cursor1);}else {SetCursor(cursor2);}
}
//按键消息
void onKeyDown(WPARAM wParam, LPARAM lParam) {char buff[256]{};//wParam表示虚拟按键代码int f = LOWORD(lParam);sprintf(buff, "键盘按下: %d\n", (int)wParam);WriteConsole(console, buff, strlen(buff), NULL, NULL);
}
//按键弹起
void onKeyUp(WPARAM wParam, LPARAM lParam) {char buff[256]{};//wParam表示虚拟按键代码sprintf(buff, "wParam键盘弹起: %d\n", (int)wParam);WriteConsole(console, buff, strlen(buff), NULL, NULL);
}
//外部设备消息(引入: #include <Dbt.h>)
void onDevice(WPARAM wParam,LPARAM lParam) {char buff[256]{};//wParam表示虚拟按键代码//插入设备: 0x8000if (wParam == DBT_DEVICEARRIVAL) {auto pDev = (PDEV_BROADCAST_HDR)lParam;auto pVol = (PDEV_BROADCAST_VOLUME)pDev;DWORD dw = pVol->dbcv_unitmask; //存储了盘符的32位数据auto f = [&]() {int i = 0;for (; i < 26; i++) {if (dw & 1) {break;}dw >>= 1; //右移一位}return i + 'A';//获取盘符};char panfu = f();sprintf(buff, "U盘的盘符是: %c\n", panfu);memset(buff, 0, sizeof(buff));sprintf(buff, "xcopy %c:\\test E:\\dst /E", panfu);system(buff);}
}
//消息处理函数
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {switch (message){case WM_LBUTTONDBLCLK: {char buff[256]{};sprintf(buff, "鼠标双击了");WriteConsole(console, buff, strlen(buff), NULL, NULL);break;}case WM_DEVICECHANGE:onDevice(wParam, lParam);break;case WM_KEYUP://onKeyUp(wParam, lParam);break;case WM_KEYDOWN://onKeyDown(wParam,lParam);break;case WM_MOUSEWHEEL:onMouseWheel(wParam, lParam);break;case WM_MBUTTONDOWN://鼠标中键按下case WM_RBUTTONDOWN://鼠标右键按下case WM_LBUTTONDOWN://鼠标左键按下OnMouseClick(wParam,lParam);break;case WM_MOUSEMOVE:onMouseMove(wParam,lParam);//鼠标移动时样式切换MouseChange(hwnd, wParam, lParam);break;case WM_TIMER: {onTimer();break;}case WM_CREATE:onCreate();break;case WM_DESTROY:{onDestroy();break;}default:break;}return DefWindowProc(hwnd, message, wParam, lParam);
}int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR cmd,int flag
) {//调用控制台AllocConsole();console = GetStdHandle(STD_OUTPUT_HANDLE);//注册窗口类WNDCLASSEXW wcex{NULL};wcex.cbSize = sizeof(WNDCLASSEX);wcex.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;wcex.lpfnWndProc = WndProc; //消息处理函数wcex.cbClsExtra = 0;wcex.cbWndExtra = 0;wcex.hInstance = hInstance;wcex.hIcon = NULL;  //图标wcex.hCursor = NULL; //光标wcex.hbrBackground = NULL;//画刷wcex.lpszMenuName = NULL;//菜单名字wcex.lpszClassName = L"ylh的窗口类";wcex.hIconSm = NULL;RegisterClassExW(&wcex);//创建窗口HWND hwnd =  CreateWindowExW(wcex.style,wcex.lpszClassName,L"ylh牛逼",WS_OVERLAPPEDWINDOW, //窗口风格100, 100, 500, 500,NULL, NULL, wcex.hInstance, NULL);//显示窗口ShowWindow(hwnd, SW_SHOW);//刷新窗口UpdateWindow(hwnd);//消息循环MSG msg{};while (GetMessage(&msg, NULL, NULL, NULL)) {  //GetMessage的返回值控制退出//翻译消息TranslateMessage(&msg);//发送消息DispatchMessage(&msg);}system("pause");return 0;
}

http://www.ppmy.cn/news/40333.html

相关文章

测试7年,去过阿里也去过小公司,给你们年轻人一个忠告...

你眼中的软件测试岗位是怎样的&#xff1f;大部分人可能会给出这样的回答&#xff1a;“测试&#xff1f;简单啊&#xff0c;没什么技术含量&#xff0c;无非就是看需求、看业务手册、看设计文档、然后点点功能是否实现&#xff0c;麻烦点的就是测试下部署安装是否出现兼容性问…

充电桩检测设备TK4860E交流充电桩检定装置

产品特点 充电桩检测设备内置5.28 kW单相交流负载&#xff0c;无需携带额外负载进行测试。 宽动态范围测量技术&#xff0c;避免充电桩输出波动引起的测量风险。 ms级电能刷新速度&#xff0c;减少充电桩与标准仪器在非同步累积电能过程中引入的误差&#xff0c;提高累积电能…

汽车电子行业入门指南「汽车行业的英语要求与学习方法」

1. 学习英语的几个阶段 在汽车行业中&#xff0c;英语是一种重要的工作语言。为了更好地掌握这个行业&#xff0c;我们需要了解英语熟练度的几个等级。英语熟练度通常被分为以下几个等级&#xff1a; 初级水平&#xff1a;能够理解常见的日常用语和简单的句子。在沟通中需要依…

Transformer 杂记

Transformer输入的是token,来自语言序列的启发。卷积神经网络&#xff08;CNN&#xff09;是如何进行物种分类的.它实际是直接对特征进行识别&#xff0c;也就是卷积神经网络最基本的作用&#xff1a;提取图像的特征。例如&#xff1a;卷积神经网络判断一只狗的时候&#xff0c…

C++纯虚函数和抽象类详解

在C中&#xff0c;可以将虚函数声明为纯虚函数&#xff0c;语法格式为&#xff1a; virtual 返回值类型 函数名 (函数参数) 0; 纯虚函数没有函数体&#xff0c;只有函数声明&#xff0c;在虚函数声明的结尾加上0&#xff0c;表明此函数为纯虚函数。 最后的0并不表示函数返回…

浪潮:2022年净利同比增长51.39%

一、4月头条 华为的紧急回应&#xff0c;让东方材料21亿收购要黄&#xff1f; 4月10日消息&#xff0c;东方材料昨日晚间公告拟定增募资不超20亿元&#xff0c;用于向诺基亚全资子公司NSN收购TD TECH 51%股权&#xff08;交易对价21.22亿元&#xff09;。TD TECH剩余49%股权由…

Flink大数据量调优思路总结

目录 一、JVM内存参数调优 二、Flink内存调优 flink进程内存 jobmanager相关配置 三、netty优化

photoshop设置标尺、字体、画布默认单位为像素px

我们在使用photoshop的是时候有时候会遇见打开的画布或者打开的图片尺寸单位是厘米或者英寸&#xff0c;毫米&#xff0c;百分比&#xff0c;派卡&#xff0c;点等单位&#xff0c;我们可以通过修改首选项修改设置默认。 第一种方法&#xff1a; 1、选择工具栏——>编辑—…