windows编程(2)-消息与循环
文章首发于:My Blog 欢迎大佬们前来逛逛
win32打开控制台的方法
首先加入输入输出头文件
-
AllocConsole
:为控制台分配空间 -
GetStdHandle
:创建一个标准输入输出设备,指定其为STD_OUTPUT_HANDLE
则就是一个标准输出控制台。 -
创建一个
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。
需要的一些操作:
- 添加资源文件(在此不多赘述)
- 加载鼠标资源:使用
LoadCursor
函数,使用MAKEINTRESOURCE
将整数值转换为与资源管理功能兼容的资源类型。 此宏用于代替包含资源名称的字符串。 - 获取窗口的宽度:
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盘上的内容:则我们可以这样操作
- 将lParam转换为
PDEV_BROADCAST_VOLUME
类型。这个结构体指针中有一个参数dbcv_unitmask
表示的是外部设备所处的盘符,因此我们便可以获取U盘的盘符,然后执行 copy操作。 dbcv_unitmask
是由右往左表示的,即最右边到左边表示‘A' B C D ....,如果是0,则表示是A盘,因此我们便可以获取盘符xcopy
的拷贝操作
//外部设备消息(引入: #include <Dbt.h>) void onDevice(WPARAM wParam,LPARAM lParam) { char buff[256]{}; //wParam表示虚拟按键代码 //插入设备: 0x8000 if (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表示虚拟按键代码 //插入设备: 0x8000 if (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; }
本文来自博客园,作者:hugeYlh,转载请注明原文链接:https://www.cnblogs.com/helloylh/p/17300981.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具