Windows C++ 任意线程通过hwnd将操作发送到UI线程执行

2024-03-10 01:44

本文主要是介绍Windows C++ 任意线程通过hwnd将操作发送到UI线程执行,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!


前言

做Windows界面开发时,经常需要在多线程环境中将操作抛到主线程执行,通常做法是定义一个WM_USER消息,将函数指针通过SendMessage发送给窗口,窗口过程中接收消息后执行函数。本文提供的方法可以在任意地方使用,不需要重新定义消息以及接收消息。


一、基本实现

只是基本的实现方法,也包含了基本原理。

1、自定义WM消息

#define  WM_INVOKE WM_USER+3328

2、发送消息

需要UI线程执行的函数

 void action(void* arg){//ui线程执行的操作}

发送到ui线程

SendMessage(hwnd, WM_INVOKE, action, arg);

3、窗口过程中执行函数

static LRESULT  wnd_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparma)
{switch (msg) {case WM_INVOKE:{	void(*action)(void* s);action = wparam;action(lparma);}break;}return 0;
}

二、优化实现

上述实现,需要在每个窗口或每个项目的窗口过程写代码,移植起来很麻烦。我们通过钩子的方式做成,实现一次到处使用
定义消息略,与基本实现一致。

1、钩子过程中执行函数

定义一个钩子过程,并在钩子过程中执行函数。

LRESULT CALLBACK hook_proc(int code, WPARAM wParam, LPARAM lParam) {CWPSTRUCT* msg = lParam;if (msg->message == WM_INVOKE) { ((void(*)(void* s)) msg->wParam)(msg->lParam);}return 0;
}

2、设置钩子

HHOOK hook = SetWindowsHookEx(WH_CALLWNDPROC, hook_proc, GetModuleHandle(NULL), GetWindowThreadProcessId(hwnd, NULL));

3、发送消息

将函数通过消息发送出去

SendMessage(hwnd, WM_INVOKE, action, arg);

4、卸载钩子

UnhookWindowsHookEx(hook);

三、完整代码

1、C

#include<Windows.h>
#define  WM_INVOKE WM_USER+3328
static LRESULT CALLBACK hook_proc(int code, WPARAM wParam, LPARAM lParam) {CWPSTRUCT* msg = lParam;if (msg->message == WM_INVOKE) { ((void(*)(void* s)) msg->wParam)(msg->lParam);}return 0;
}
/// <summary>
/// 将操作切换到窗口线程执行,同步。
/// </summary>
/// <param name="hwnd">窗口句柄</param>
/// <param name="action">执行的操作</param>
/// <param name="arg">透传参数</param>
void invoke(HWND hwnd, void(*action)(void* arg), void* arg) {if (GetCurrentThreadId() != GetWindowThreadProcessId(hwnd, NULL)) {HHOOK hook = SetWindowsHookEx(WH_CALLWNDPROC, hook_proc, GetModuleHandle(NULL), GetWindowThreadProcessId(hwnd, NULL));SendMessage(hwnd, WM_INVOKE, action, arg);UnhookWindowsHookEx(hook);}else action(arg);
}

1、C++

与c的区别是,能使用std::function,可捕获变量。

#include<Windows.h>
#include<functional>
#define  WM_INVOKE WM_USER+3328
static LRESULT CALLBACK hook_proc(int code, WPARAM wParam, LPARAM lParam) {CWPSTRUCT* msg = (CWPSTRUCT*)lParam;if (msg->message == WM_INVOKE) {(*((std::function<void()>*) msg->wParam))();}return 0;
}
/// <summary>
/// 将操作切换到窗口线程执行,同步。
/// </summary>
/// <param name="hwnd">窗口句柄</param>
/// <param name="func">执行的操作</param>
void invoke(HWND hwnd, const std::function<void()>& func) {if (GetCurrentThreadId() != GetWindowThreadProcessId(hwnd, NULL)) {HHOOK hook = SetWindowsHookEx(WH_CALLWNDPROC, hook_proc, GetModuleHandle(NULL), GetWindowThreadProcessId(hwnd, NULL));SendMessage(hwnd, WM_INVOKE, (WPARAM)&func, 0);UnhookWindowsHookEx(hook);}else func();
}

四、使用示例

1、C

void action(void* arg)
{printf("invoked %d\n",(int)arg);
}
invoke(hwnd,action,123)

2、C++

int a=123;
invoke(hwnd, [&]() {printf("invoked %d\n", a);});

总结

以上就是今天要讲的内容,本文仅仅简单的实现了通用的线程invoke,且只支持同步,通用的异步invoke实现稍微复杂些(基本实现的方式则比较简单),以后有空再做。总的来说,有了本文的代码很大程度的方便了使用,尤其是一个新的项目突然需要invoke功能,按照基本实现的方式在窗口中写一遍是很麻烦的,而优化的实现则可以直接复用,调用invoke即可。

这篇关于Windows C++ 任意线程通过hwnd将操作发送到UI线程执行的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/792612

相关文章

使用MongoDB进行数据存储的操作流程

《使用MongoDB进行数据存储的操作流程》在现代应用开发中,数据存储是一个至关重要的部分,随着数据量的增大和复杂性的增加,传统的关系型数据库有时难以应对高并发和大数据量的处理需求,MongoDB作为... 目录什么是MongoDB?MongoDB的优势使用MongoDB进行数据存储1. 安装MongoDB

Linux使用fdisk进行磁盘的相关操作

《Linux使用fdisk进行磁盘的相关操作》fdisk命令是Linux中用于管理磁盘分区的强大文本实用程序,这篇文章主要为大家详细介绍了如何使用fdisk进行磁盘的相关操作,需要的可以了解下... 目录简介基本语法示例用法列出所有分区查看指定磁盘的区分管理指定的磁盘进入交互式模式创建一个新的分区删除一个存

Golang操作DuckDB实战案例分享

《Golang操作DuckDB实战案例分享》DuckDB是一个嵌入式SQL数据库引擎,它与众所周知的SQLite非常相似,但它是为olap风格的工作负载设计的,DuckDB支持各种数据类型和SQL特性... 目录DuckDB的主要优点环境准备初始化表和数据查询单行或多行错误处理和事务完整代码最后总结Duck

C# 读写ini文件操作实现

《C#读写ini文件操作实现》本文主要介绍了C#读写ini文件操作实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录一、INI文件结构二、读取INI文件中的数据在C#应用程序中,常将INI文件作为配置文件,用于存储应用程序的

Python使用qrcode库实现生成二维码的操作指南

《Python使用qrcode库实现生成二维码的操作指南》二维码是一种广泛使用的二维条码,因其高效的数据存储能力和易于扫描的特点,广泛应用于支付、身份验证、营销推广等领域,Pythonqrcode库是... 目录一、安装 python qrcode 库二、基本使用方法1. 生成简单二维码2. 生成带 Log

Java操作ElasticSearch的实例详解

《Java操作ElasticSearch的实例详解》Elasticsearch是一个分布式的搜索和分析引擎,广泛用于全文搜索、日志分析等场景,本文将介绍如何在Java应用中使用Elastics... 目录简介环境准备1. 安装 Elasticsearch2. 添加依赖连接 Elasticsearch1. 创

C++中实现调试日志输出

《C++中实现调试日志输出》在C++编程中,调试日志对于定位问题和优化代码至关重要,本文将介绍几种常用的调试日志输出方法,并教你如何在日志中添加时间戳,希望对大家有所帮助... 目录1. 使用 #ifdef _DEBUG 宏2. 加入时间戳:精确到毫秒3.Windows 和 MFC 中的调试日志方法MFC

java Stream操作转换方法

《javaStream操作转换方法》文章总结了Java8中流(Stream)API的多种常用方法,包括创建流、过滤、遍历、分组、排序、去重、查找、匹配、转换、归约、打印日志、最大最小值、统计、连接、... 目录流创建1、list 转 map2、filter()过滤3、foreach遍历4、groupingB

Java操作PDF文件实现签订电子合同详细教程

《Java操作PDF文件实现签订电子合同详细教程》:本文主要介绍如何在PDF中加入电子签章与电子签名的过程,包括编写Word文件、生成PDF、为PDF格式做表单、为表单赋值、生成文档以及上传到OB... 目录前言:先看效果:1.编写word文件1.2然后生成PDF格式进行保存1.3我这里是将文件保存到本地后

windows系统下shutdown重启关机命令超详细教程

《windows系统下shutdown重启关机命令超详细教程》shutdown命令是一个强大的工具,允许你通过命令行快速完成关机、重启或注销操作,本文将为你详细解析shutdown命令的使用方法,并提... 目录一、shutdown 命令简介二、shutdown 命令的基本用法三、远程关机与重启四、实际应用