C++第五十六篇——VC获取显示器状态(捕获熄屏/亮屏)
参考链接:https://blog.csdn.net/rocklee/article/details/76636253
此篇文章实现C++可以获取屏幕亮灭的消息,程序在后台运行,不会有控制台窗口显示。
第一步:新建一个控制台程序
第二步:编写屏幕亮灭的代码
ScreenTest.cpp
#include <windows.h> #include <iostream> using namespace std; #pragma comment(linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"") FILE* Log; LRESULT CALLBACK WindowProc( _In_ HWND hwnd, _In_ UINT uMsg, _In_ WPARAM wParam, _In_ LPARAM lParam ); HWND createMsgWin() { HINSTANCE lvhInstance; lvhInstance = GetModuleHandle(NULL); //获取一个应用程序或动态链接库的模块句柄 WNDCLASS lvwcCls; lvwcCls.cbClsExtra = 0; lvwcCls.cbWndExtra = 0; lvwcCls.hCursor = LoadCursor(lvhInstance, IDC_ARROW); //鼠标风格 lvwcCls.hIcon = LoadIcon(lvhInstance, IDI_APPLICATION); //图标风格 lvwcCls.lpszMenuName = NULL; //菜单名 lvwcCls.style = CS_HREDRAW | CS_VREDRAW; //窗口的风格 lvwcCls.hbrBackground = (HBRUSH)COLOR_WINDOW; //背景色 lvwcCls.lpfnWndProc = WindowProc; //【关键】采用自定义消息处理函数,也可以用默认的DefWindowProc lvwcCls.lpszClassName = L"RenderWindow"; //【关键】该窗口类的名称 lvwcCls.hInstance = lvhInstance; //【关键】表示创建该窗口的程序的运行实体代号 RegisterClass(&lvwcCls); HWND lvhwndWin = CreateWindow( L"RenderWindow", //【关键】上面注册的类名lpszClassName,要完全一致 L"Zombie", //窗口标题文字 WS_OVERLAPPEDWINDOW, //窗口外观样式 0, //窗口相对于父级的X坐标 0, //窗口相对于父级的Y坐标 30, //窗口的宽度 20, //窗口的高度 NULL, //没有父窗口,为NULL NULL, //没有菜单,为NULL lvhInstance, //当前应用程序的实例句柄 NULL); //没有附加数据,为NULL //去标题栏 return lvhwndWin; } LRESULT CALLBACK WindowProc( _In_ HWND hwnd, _In_ UINT uMsg, _In_ WPARAM wParam, _In_ LPARAM lParam ) { //cout << "MSG:" << uMsg << ",wParam:" << wParam << ",lParam:" << lParam << endl; switch (uMsg) { case WM_POWERBROADCAST: { if (wParam == PBT_POWERSETTINGCHANGE) { POWERBROADCAST_SETTING* lvpsSetting = (POWERBROADCAST_SETTING*)lParam; byte lvStatus = *(lvpsSetting->Data); if (lvStatus != 0) { cout << "Monitor is turn on" << endl; fprintf(Log, "Monitor is turn on\n"); fflush(Log); } else { cout << "Monitor is turn off" << endl; fprintf(Log, "Monitor is off\n"); fflush(Log); } //cout << (int)lvStatus << endl; } break; } } return DefWindowProc(hwnd, uMsg, wParam, lParam); } HWND mhMsgRec; BOOL WINAPI ConsoleHandler(DWORD pvdwMsgType) { if (pvdwMsgType == CTRL_C_EVENT) { PostMessage(mhMsgRec, WM_DESTROY, 0, 0); return TRUE; } else if (pvdwMsgType == CTRL_CLOSE_EVENT) { PostMessage(mhMsgRec, WM_DESTROY, 0, 0); return TRUE; } return FALSE; } int main() { errno_t err; // 尝试以写入模式打开文件 err = fopen_s(&Log, "D:\\ScreenTest.log", "w"); if (err != 0) { perror("Error opening file"); return EXIT_FAILURE; } // 写入数据到文件 fprintf(Log, "main\n"); // 刷新输出缓冲区,确保数据被写入文件 fflush(Log); mhMsgRec = createMsgWin();//这个函数也是dll里的,得到控制台的句柄 HPOWERNOTIFY lvhpNotify = RegisterPowerSettingNotification(mhMsgRec, &GUID_CONSOLE_DISPLAY_STATE, DEVICE_NOTIFY_WINDOW_HANDLE); SetConsoleCtrlHandler(ConsoleHandler, TRUE); bool lvbRet; MSG lvMSG; while ((lvbRet = GetMessage(&lvMSG, NULL, 0, 0)) != 0) { TranslateMessage(&lvMSG); DispatchMessage(&lvMSG); if (lvMSG.message == WM_DESTROY) { break; } } UnregisterPowerSettingNotification(lvhpNotify); CloseWindow(mhMsgRec); return 0; }
第三步:生成EXE
第四步:双击运行EXE,在任务管理器进程中检查EXE是否在后台运行
第五步:在任务管理器中结束EXE任务,查看Log中是否有打印消息。
至此,程序功能实现。
注意一点:#pragma comment(linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"")这句话就是让程序在后台运行。不过它还有个相关设置如下