宁波cms建站界面设计排版
- 作者: 五速梦信息网
- 时间: 2026年03月21日 10:15
当前位置: 首页 > news >正文
宁波cms建站,界面设计排版,微信怎么开通公众号,大型网站建设企业目录 前言 1 遍历窗口句柄列表 2 使用 SendMessageTimeout 发送延时消息 3 并行发送消息实现模拟广播消息 4 修改 UIPI 消息过滤器设置 5 托盘图标刷新的处理 6 完整代码和测试 本文属于原创文章#xff0c;转载请注明出处#xff1a; https://blog.csdn.net/qq_5907…目录 前言 1 遍历窗口句柄列表 2 使用 SendMessageTimeout 发送延时消息 3 并行发送消息实现模拟广播消息 4 修改 UIPI 消息过滤器设置 5 托盘图标刷新的处理 6 完整代码和测试 本文属于原创文章转载请注明出处 https://blog.csdn.net/qq_59075481/article/details/136175227。 前言 在 Windows 上使得设置的更改立即生效的方法不唯一。本文分析全局发送 WM_SETTINGCHANGE 消息来通知系统设置发生更改这一方法。该方法适用范围比较广泛但有时候还是需要结合 SHChangeNotify 等函数来刷新更改甚至还有一部分设置更改就只能重启计算机生效。 我们知道如果使用 HWND_BROADCAST 广播消息的话虽然会通知所有顶级窗口只消息窗口等窗口但是该消息的处理在任意一个窗口处理后就会立即终止并返回消息接收方有权不处理消息我们并不容易获取消息处理的详细情况并且他不能针对子窗口等窗口。 所以我们肯定要自己去实现自己的广播消息的方式。 1 遍历窗口句柄列表 我们首先通过 EnumWindows 和 EnumChildWindows 以递归的方式遍历获取所有窗口句柄列表。 // Callback function for window enumeration BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam) {// Cast the lParam to a vector of HWND pointersstd::vectorHWND* windowList reinterpret_caststd::vectorHWND(lParam);// Add the window handle to the vectorwindowList-push_back(hwnd);// Enumerate child windowsEnumChildWindows(hwnd, EnumWindowsProc, lParam);// Continue enumerationreturn TRUE; }// Enumerate all windows std::vectorHWND windowList; EnumWindows(EnumWindowsProc, reinterpret_castLPARAM(windowList)); 2 使用 SendMessageTimeout 发送延时消息 SendMessageTimeout 的好处是它可以比 SendMessage 多出来等待时间这个限制SendMessage 会阻滞调用线程直到接收消息的线程处理完消息所以不能用 SendMessage 同时发送消息到多个窗口它比 PostMessage 也有优势PostMessage 立即返回所以在不关心处理结果的情况下我们可能选择 PostMessage。 SendMessageTimeout 函数的声明如下 LRESULT SendMessageTimeoutW(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam,UINT fuFlags,UINT uTimeout,PDWORD_PTR lpdwResult ); 我们使用该函数就可以实现发送消息并等待一定时间MSDN 说明如下 https://learn.microsoft.com/zh-cn/windows/win32/api/winuser/nf-winuser-sendmessagetimeouta。 3 并行发送消息实现模拟广播消息 单线程似乎并不能满足我们同时请求多个窗口的需求。所以我们可以将处理放置在多线程任务中。并将消息处理的结果使用链表来管理。 数据结构 typedef struct __STMO_MSGEVENT {SIZE_T nCount;SIZE_T nSize;HWND hWnd;BOOL isActive;LRESULT lResult;DWORD_PTR lpStatus;struct __STMO_MSGEVENT pNext[1]; } STMO_MSGEVENT, * LPSTMO_MSGEVENT; 其中isActive 表示接收消息的线程是否在规定时间处理了消息nSize 表示结点总数头结点的nCount 表示所有窗口个数。 线程执行函数 // Function to send message to a window using SendMessageTimeout void SendMessageToWindow(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LPSTMO_MSGEVENT* lpstmoMsg) {// Set the timeout value (in milliseconds)DWORD timeout 5000;// Call ChangeWindowsMessageFilterEx to modify the message filterChangeWindowMessageFilterEx(hwnd, uMsg, MSGFLT_ALLOW, 0);// Send the message using SendMessageTimeoutDWORD_PTR lpStatus 0;LRESULT lResult 0;lResult SendMessageTimeoutW(hwnd, uMsg, wParam, lParam, SMTO_ABORTIFHUNG, timeout, lpStatus);bool oldCount lResult 0 ? true : false;AddNode(lpstmoMsg, hwnd, oldCount, lResult, lpStatus);} 4 修改 UIPI 消息过滤器设置 从 Vista 引入的消息安全机制将限制低完整级别程序向高完整级别程序发送消息的过程此时可以使用 ChangeWindowMessageFilterEx 来允许特定的消息通过 UIPI。 // Call ChangeWindowsMessageFilterEx to modify the message filter ChangeWindowMessageFilterEx(hwnd, uMsg, MSGFLT_ALLOW, 0); 指定 MSGFLT_ALLOW 以允许消息通过 UIPI。 5 托盘图标刷新的处理 托盘图标刷新需要单独模拟发送 TaskbarCreated 消息。在任务栏重建时会向系统中所有窗口广播 TaskbarCreated 消息在负责通知栏图标的线程接收到消息时接收消息的线程按照规范应该调用 Shell_NotifyIcon 重新创建通知栏图标。 TaskbarCreated 字符串消息是通过 RegisterWindowMessage 在系统级别注册的因为该函数内部封装了 NtUserRegisterWindowMessage 的调用这是一个用户态/内核态切换过程。通过逆向分析我们了解到 RegisterWindowMessage 的返回值是 Global ATOM 数值的一部分系统内核在全局维护一个原子表 RTL_ATOM_TABLE 来通过哈希桶管理一些窗口进程交互需要的信息。 所以在系统重启前TaskbarCreated 消息对应的 IntAtom 索引号保持不变该值与 explorer 的重启无关。 调用 RegisterWindowMessage 并指定 TaskbarCreated 字符串将首先检索消息是否已经在 ATOM 表中注册。由于该消息在系统初始化时已经注册所以执行过程只会增加该消息的引用计数而不会重建消息。 所以我们可以利用 RegisterWindowMessage 作为一个官方支持的技巧轻松获取TaskbarCreated消息的窗口消息码调用在非消息线程/非窗口进程/非系统进程就可以调用成功。所以该消息不会失败除非交互系统未能够完成初始化。 // 该字符串消息使用系统原子表返回值是 IntAtom 编号 // 一般情况下在计算机重启时才刷新。 UINT QueryTaskbarCreateMsg() {return RegisterWindowMessageW(LTaskbarCreated); } 6 完整代码和测试 #include Windows.h #include iostream #include vector #include thread#pragma comment(lib, User32.lib)typedef struct __STMO_MSGEVENT {SIZE_T nCount;HWND hWnd;BOOL isActive;LRESULT lResult;DWORD_PTR lpStatus;struct __STMO_MSGEVENT* pNext[1]; } STMO_MSGEVENT, * LPSTMO_MSGEVENT;LPSTMO_MSGEVENT CreateNode(HWND hWnd) {LPSTMO_MSGEVENT newNode (LPSTMO_MSGEVENT)malloc(sizeof(STMO_MSGEVENT));newNode-nCount 0;newNode-hWnd hWnd;newNode-isActive FALSE;newNode-lResult 0;newNode-lpStatus 0;return newNode; }void AddNode(LPSTMO_MSGEVENT* pList, HWND hWnd, LRESULT lResult, DWORD_PTR lpStatus) {LPSTMO_MSGEVENT newNode CreateNode(hWnd);newNode-isActive (lResult 0);newNode-lResult lResult;newNode-lpStatus lpStatus;newNode-pNext[0] *pList;*pList newNode;(pList)-nCount; }void SendMessageToWindow(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LPSTMO_MSGEVENT lpstmoMsg) {DWORD timeout 5000;ChangeWindowMessageFilterEx(hwnd, uMsg, MSGFLT_ALLOW, 0);DWORD_PTR lpStatus 0;LRESULT lResult SendMessageTimeoutW(hwnd, uMsg, wParam, lParam, SMTO_ABORTIFHUNG, timeout, lpStatus);//LPSTMO_MSGEVENT newNode CreateNode(hwnd);//newNode-isActive (lResult 0);// newNode-lResult lResult;//newNode-lpStatus lpStatus;AddNode(lpstmoMsg, hwnd, lResult, lpStatus); }BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam) {std::vectorHWND* windowList reinterpret_caststd::vectorHWND(lParam);windowList-push_back(hwnd);EnumChildWindows(hwnd, EnumWindowsProc, lParam);return TRUE; }void TraverseList(LPSTMO_MSGEVENT pList) {LPSTMO_MSGEVENT pNode pList;while (pNode ! nullptr) {std::cout hWnd: pNode-hWnd std::endl;std::cout isActive: (pNode-isActive ? true : false) std::endl;std::cout lResult: pNode-lResult lpStatus: pNode-lpStatus std::endl;pNode pNode-pNext[0];} }void FreeList(LPSTMO_MSGEVENT pList) {LPSTMO_MSGEVENT pNode *pList;while (pNode ! nullptr) {LPSTMO_MSGEVENT temp pNode;pNode pNode-pNext[0];free(temp);}pList nullptr; }// 该字符串消息使用系统原子表返回值是 IntAtom 编号 // 一般情况下在计算机重启时才刷新。 UINT QueryTaskbarCreateMsg() {return RegisterWindowMessageW(LTaskbarCreated); }int main() {std::vectorHWND windowList;EnumWindows(EnumWindowsProc, reinterpret_castLPARAM(windowList));SendMessage(HWND_BROADCAST, WM_SETTINGCHANGE, SPI_SETNONCLIENTMETRICS, 0);std::vectorstd::thread threads;UINT uMsg WM_SETTINGCHANGE;WPARAM wParam SPI_SETNONCLIENTMETRICS;LPARAM lParam (LPARAM)0;LPSTMO_MSGEVENT msgev nullptr;for (HWND hwnd : windowList){threads.emplace_back(SendMessageToWindow, hwnd, uMsg, wParam, lParam, msgev);}for (std::thread thread : threads){thread.join();}std::cout List contents:\n;TraverseList(msgev);FreeList(msgev);return 0; }#include Windows.h #include iostream #include vector #include threadtypedef struct __STMO_MSGEVENT {SIZE_T nCount;SIZE_T nSize;HWND hWnd;BOOL isActive;LRESULT lResult;DWORD_PTR lpStatus;struct __STMO_MSGEVENT pNext[1]; } STMO_MSGEVENT, * LPSTMO_MSGEVENT;LPSTMO_MSGEVENT CreateNode(HWND hWnd, BOOL isActive, LRESULT lResult, DWORD_PTR lpStatus, SIZE_T nCount) {LPSTMO_MSGEVENT newNode (LPSTMO_MSGEVENT)malloc(sizeof(STMO_MSGEVENT));newNode-nCount nCount;newNode-nSize 1;newNode-hWnd hWnd;newNode-isActive isActive;newNode-lResult lResult;newNode-lpStatus lpStatus;return newNode; }LPSTMO_MSGEVENT InitializeList(SIZE_T initialSize) {LPSTMO_MSGEVENT newList (LPSTMO_MSGEVENT)malloc(sizeof(STMO_MSGEVENT) initialSize * sizeof(LPSTMO_MSGEVENT));if (newList ! NULL) {memset(newList, 0, sizeof(LPSTMO_MSGEVENT) * initialSize sizeof(STMO_MSGEVENT));newList-nCount 1;newList-nSize initialSize;newList-hWnd NULL;newList-isActive FALSE;newList-lResult 0;newList-lpStatus 0;return newList;}else {printf(Failed to allocate memory for the list.\n);return NULL;} }void AddNode(LPSTMO_MSGEVENT* pList, HWND hWnd, BOOL isActive, LRESULT lResult, DWORD_PTR lpStatus) {LPSTMO_MSGEVENT newNode CreateNode(hWnd, isActive, lResult, lpStatus, (*pList)-nCount); // 也可以固定为 nSize这只是一个记录if ((*pList)-nCount (*pList)-nSize) {(*pList)-pNext[(*pList)-nCount] newNode;(*pList)-nCount;}else {SIZE_T newSize (*pList)-nSize * 2;LPSTMO_MSGEVENT newList (LPSTMO_MSGEVENT)realloc(*pList, sizeof(STMO_MSGEVENT) newSize * sizeof(LPSTMO_MSGEVENT));if (newList ! NULL) {memset(newList, 0, sizeof(LPSTMO_MSGEVENT) * newSize sizeof(STMO_MSGEVENT));*pList newList;(*pList)-pNext[(*pList)-nCount] newNode;(*pList)-nCount;(pList)-nSize newSize;}else {free(newNode);printf(Failed to allocate memory for the new node.\n);}} }void TraverseList(LPSTMO_MSGEVENT pList) {for (SIZE_T i 0; i pList-nCount; i) {LPSTMO_MSGEVENT pNode pList-pNext[i];std::cout index: 0x i std::endl;std::cout hWnd: pNode-hWnd std::endl;std::cout isActive: (pNode-isActive ? true : false) std::endl;std::cout lResult: pNode-lResult lpStatus: pNode-lpStatus std::endl;} }void FreeList(LPSTMO_MSGEVENT pList) {for (SIZE_T i 0; i (*pList)-nCount; i) {free((*pList)-pNext[i]);}free(*pList);pList NULL; }// Function to send message to a window using SendMessageTimeout void SendMessageToWindow(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LPSTMO_MSGEVENT lpstmoMsg) {// Set the timeout value (in milliseconds)DWORD timeout 5000;// Call ChangeWindowsMessageFilterEx to modify the message filterChangeWindowMessageFilterEx(hwnd, uMsg, MSGFLT_ALLOW, 0);// Send the message using SendMessageTimeoutDWORD_PTR lpStatus 0;LRESULT lResult 0;lResult SendMessageTimeoutW(hwnd, uMsg, wParam, lParam, SMTO_ABORTIFHUNG, timeout, lpStatus);bool oldCount lResult 0 ? true : false;AddNode(lpstmoMsg, hwnd, oldCount, lResult, lpStatus);}// 该字符串消息使用系统原子表返回值是 IntAtom 编号 // 一般情况下在计算机重启时才刷新。 UINT QueryTaskbarCreateMsg() {return RegisterWindowMessageW(LTaskbarCreated); }// Callback function for window enumeration BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam) {// Cast the lParam to a vector of HWND pointersstd::vectorHWND* windowList reinterpret_caststd::vectorHWND*(lParam);// Add the window handle to the vectorwindowList-push_back(hwnd);// Enumerate child windowsEnumChildWindows(hwnd, EnumWindowsProc, lParam);// Continue enumerationreturn TRUE; }int main() {// Enumerate all windowsstd::vectorHWND windowList;EnumWindows(EnumWindowsProc, reinterpret_castLPARAM(windowList));// 要刷新任务栏的话用这个消息即可UINT uTaskbarMsg QueryTaskbarCreateMsg();std::cout TaskbarCreateMsgAtom: 0x std::hex uTaskbarMsg std::endl;HWND hWnd FindWindowW(LShell_TrayWnd, nullptr);// Create a vector of threadsstd::vectorstd::thread threads;UINT uMsg WM_SETTINGCHANGE; // uTaskbarMsg;WPARAM wParam (WPARAM)0; // hWnd;LPARAM lParam 0;LPSTMO_MSGEVENT msgev InitializeList(1024);// Launch threads to send messages to windowsfor (HWND hwnd : windowList){// Create a thread and pass the window handle as an argumentthreads.emplace_back(SendMessageToWindow, hwnd, uMsg, wParam, lParam, msgev);}// Wait for all threads to finishfor (std::thread thread : threads){thread.join();}// Traverse and print the listprintf(List contents:\n);TraverseList(msgev);// Free the listFreeList(msgev);return 0; } P.S. : 为了便于测试我们选用了任务栏重建时的 TaskbarCreated 消息作为示例这只会通知更新托盘图标如果要全局通知系统设置更改应该用 WM_SETTINGCHANGE 消息但由于 WM_SETTINGCHANGE 是一瞬间的不方便截图所以我只给出了 Taskbar Create 消息测试的结果。但是在上面的代码中我使用 WM_SETTINGCHANGE 并注释了 Taskbar Create 消息。 操作需要提升管理员权限否则部分窗口可能因为 UIPI 过滤而无法接收到消息。 我们开起了一个托盘图标窗口程序用于在接收到 TASKBAR_CREATED 消息时弹出消息框。 使用上文代码工具广播消息时程序成功受到广播的信息 广播结果截图 测试程序的图标 本文属于原创文章转载请注明出处 https://blog.csdn.net/qq_59075481/article/details/136175227。 文章发布于2024.02.19更新于2024.02.20。
- 上一篇: 宁安市建设局网站网站建设中期检查表怎么写
- 下一篇: 宁波h5建站中铁十六门网户登录
相关文章
-
宁安市建设局网站网站建设中期检查表怎么写
宁安市建设局网站网站建设中期检查表怎么写
- 技术栈
- 2026年03月21日
-
宁安市建设局网站搭建简单网站
宁安市建设局网站搭建简单网站
- 技术栈
- 2026年03月21日
-
您与此网站建立的连接不安全义乌市网站建设
您与此网站建立的连接不安全义乌市网站建设
- 技术栈
- 2026年03月21日
-
宁波h5建站中铁十六门网户登录
宁波h5建站中铁十六门网户登录
- 技术栈
- 2026年03月21日
-
宁波seo排名方案seo博客网站
宁波seo排名方案seo博客网站
- 技术栈
- 2026年03月21日
-
宁波seo网站东莞非凡网站建设
宁波seo网站东莞非凡网站建设
- 技术栈
- 2026年03月21日
