当前位置: 首页 > news >正文

深入理解和实现Windows进程间通信(消息队列)

常见的进程间通信方法

常见的进程间通信方法有:

  1. 管道(Pipe)
  2. 消息队列
  3. 共享内存
  4. 信号量
  5. 套接字

下面,我们将详细介绍消息队列的原理以及具体实现。

什么是消息队列?

Windows操作系统使用消息机制来促进应用程序与操作系统之间的通信。每当发生事件(如键盘按键、鼠标移动或系统事件)时,操作系统都会生成相应的消息。这些消息被发送到一个特定的消息队列中,随后由应用程序的消息循环处理。

消息队列

每个创建了窗口的线程都拥有一个消息队列,用于存储等待处理的消息。这些消息包括用户动作(如鼠标点击、键盘操作)和系统通知(如窗口重绘请求、系统关闭通知)。

消息循环

线程通过一个循环机制,称为消息循环或消息泵,从其消息队列中检索消息。消息循环的基本操作包括:

  • 检索消息:使用GetMessagePeekMessage
  • 翻译消息TranslateMessage转换键盘输入。
  • 分发消息DispatchMessage将消息派发给目标窗口的窗口过程。

消息分类

消息主要包含:

  • 系统消息:涉及窗口生命周期管理,如WM_CLOSEWM_QUIT等。
  • 硬件消息:反映用户与硬件的交互,如WM_KEYDOWNWM_MOUSEMOVE等。

除了上面提到的消息外,用户还可以自定义消息,自定义消息一般从WM_USER(0x0400)开始,到0x7FFF这样一个范围内,比如:
#define WM_CUSTOM_MSG WM_USER+100

接口介绍

GetMessagePeekMessageSendMessagePostMessage这四个接口是Windows消息处理的核心,它们各自承担着不同的角色和功能。

GetMessage

原型

BOOL GetMessage(LPMSG lpMsg,HWND  hWnd,UINT  wMsgFilterMin,UINT  wMsgFilterMax
);

参数解释

  • lpMsg:指向MSG结构的指针,该结构将接收消息的详细信息。
  • hWnd:指定窗口的句柄,如果为NULL,则接收属于调用线程的任何窗口的消息。
  • wMsgFilterMinwMsgFilterMax:指定要检索的消息范围的最小值和最大值。如果两者都为0,函数将返回所有可用的消息。

功能和特点

  • GetMessage用于从调用线程的消息队列中检索消息。该函数在有消息到达时返回,如果遇到退出消息WM_QUIT,则返回FALSE
  • 该函数是阻塞的,如果没有消息,它会等待消息的到来。

PeekMessage

原型

BOOL PeekMessage(LPMSG lpMsg,HWND  hWnd,UINT  wMsgFilterMin,UINT  wMsgFilterMax,UINT  wRemoveMsg
);

参数解释

  • lpMsg:指向MSG结构的指针,该结构将接收消息的详细信息。
  • hWnd:指定窗口的句柄,如果为NULL,则获取属于调用线程的任何窗口的消息。
  • wMsgFilterMinwMsgFilterMax:指定要检索的消息范围的最小值和最大值。
  • wRemoveMsg:指定消息如何处理。常用值有:PM_REMOVEPM_NOREMOVE

功能和特点

  • PeekMessage用于非阻塞地检查调用线程的消息队列,允许你查看消息队列中的消息而不必移除它。
  • 可以配置为从队列中移除消息或仅检查消息而不移除。
  • 常用于动画或游戏编程中,确保应用程序保持响应用户操作,同时继续进行其它处理。

SendMessage

原型

LRESULT SendMessage(HWND   hWnd,UINT   Msg,WPARAM wParam,LPARAM lParam
);

参数解释

  • hWnd:接收消息的窗口的句柄。
  • Msg:消息的标识符。
  • wParamlParam:消息特定的附加信息。

功能和特点

  • SendMessage同步发送消息,调用方在接收窗口处理该消息之前会阻塞。
  • 可用于发送任何类型的消息,并且能够获取消息处理的结果。

PostMessage

原型

BOOL PostMessage(HWND   hWnd,UINT   Msg,WPARAM wParam,LPARAM lParam
);

参数解释

  • hWnd:接收消息的窗口的句柄。
  • Msg:消息的标识符。
  • wParamlParam:消息特定的附加信息。

功能和特点

  • PostMessage异步发送消息,将消息放入消息队列后立即返回,不等待消息被处理。
  • 适合用于那些不需要立即反馈的消息发送,如状态更新或通知消息。

实现

问题

实现两个进程,进程1发送消息给进程2,相关代码如下:

// 进程1
int main()
{HWND hWnd = FindWindow(NULL, L"WindowsProject1"); // 找到进程2的句柄const wchar_t* message = L"Hello!";if (hWnd != NULL) {SendMessage(hWnd, WM_USER+100, 0, (LPARAM)message);}std::cin.get();
}
// 进程2
#define WM_CUSTOMMSG   (WM_USER+100)
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{switch (message){case WM_CUSTOMMSG: {wchar_t* receivedMessage = reinterpret_cast<wchar_t*>(lParam);SetWindowText(hLabel, receivedMessage);}break;...}return 0;
}

进程1通过自定义消息(WM_USER+100)发送了一个字符串给进程2,进程2的确收到了消息,但是数据获取失败。

因为进程1准备发送的数据存储在进程1的虚拟内存中,进程2是无法通过地址来获取这个数据的,所以进程2虽然收到消息了,但是无法得到对应的数据。

所以在进程间通过消息队列通信时需要保证传递的数据的安全性。

WM_COPYDATA

WM_COPYDATA是一个Windows消息,用于在Windows应用程序之间传递数据。这个消息特别适用于跨进程通信,允许一个应用程序向另一个应用程序的窗口发送数据,无论这些数据是简单的数值、字符串还是更复杂的结构通。

原理

当一个应用程序需要向另一个应用程序发送数据时,它可以将数据封装在COPYDATASTRUCT结构中,并通过SendMessage函数发送WM_COPYDATA消息。当接收窗口的窗口过程收到这条消息时,它可以从COPYDATASTRUCT结构中提取数据。

COPYDATASTRUCT结构

这个结构用于封装要传递的数据,其定义如下:

typedef struct tagCOPYDATASTRUCT {ULONG_PTR dwData;  // 任意值,由发送方设置,接收方可以用它来识别数据DWORD cbData;      // lpData指向的数据的大小,以字节为单位PVOID lpData;      // 指向要传递的数据的指针
} COPYDATASTRUCT, *PCOPYDATASTRUCT;
  • dwData:这是一个用户定义的数据值,发送方可以使用它来传递额外的信息或数据类型标识,接收方则可以用它来决定如何解释接收到的数据。
  • cbData:这表示 lpData 指向的数据的大小(以字节为单位)。
  • lpData:这是一个指针,指向实际要传输的数据。

实现代码

进程1代码

int main()
{HWND hWnd = FindWindow(NULL, L"WindowsProject1");const wchar_t* message = L"Hello!";if (hWnd != NULL) {COPYDATASTRUCT cds;cds.dwData = 1;  // 用于识别数据的自定义标识cds.cbData = (wcslen(message) + 1) * sizeof(wchar_t);  // 包括终止符的大小cds.lpData = (void*)message;SendMessage(hWnd, WM_COPYDATA, (WPARAM)hWnd, (LPARAM)&cds);}std::cin.get();
}

进程2代码

HWND hLabel;
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{hInst = hInstance; // 将实例句柄存储在全局变量中HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);if (!hWnd){return FALSE;}hLabel = CreateWindowW(L"STATIC", L"Waiting for message...",WS_CHILD | WS_VISIBLE | SS_LEFT,10, 10, 300, 20,hWnd, (HMENU)1, hInstance, nullptr);ShowWindow(hWnd, nCmdShow);UpdateWindow(hWnd);return TRUE;
}LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{switch (message){case WM_COPYDATA: {PCOPYDATASTRUCT pCds = (PCOPYDATASTRUCT)lParam;if (pCds->dwData == 1) {const wchar_t* receivedStr = (const wchar_t*)pCds->lpData;SetWindowText(hLabel, receivedStr);}}break;case WM_COMMAND:{int wmId = LOWORD(wParam);// 分析菜单选择:switch (wmId){case IDM_ABOUT:DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);break;case IDM_EXIT:DestroyWindow(hWnd);break;default:return DefWindowProc(hWnd, message, wParam, lParam);}}break;case WM_PAINT:{PAINTSTRUCT ps;HDC hdc = BeginPaint(hWnd, &ps);// TODO: 在此处添加使用 hdc 的任何绘图代码...EndPaint(hWnd, &ps);}break;case WM_DESTROY:PostQuitMessage(0);break;default:return DefWindowProc(hWnd, message, wParam, lParam);}return 0;
}

效果

image.png

相关文章:

深入理解和实现Windows进程间通信(消息队列)

常见的进程间通信方法 常见的进程间通信方法有&#xff1a; 管道&#xff08;Pipe&#xff09;消息队列共享内存信号量套接字 下面&#xff0c;我们将详细介绍消息队列的原理以及具体实现。 什么是消息队列&#xff1f; Windows操作系统使用消息机制来促进应用程序与操作系…...

Web网页前端教程免费:引领您踏入编程的奇幻世界

Web网页前端教程免费&#xff1a;引领您踏入编程的奇幻世界 在当今数字化时代&#xff0c;Web前端技术已成为互联网发展的重要驱动力。想要踏入这一领域&#xff0c;掌握相关技能&#xff0c;却苦于找不到合适的教程&#xff1f;别担心&#xff0c;本文将为您带来一份免费的We…...

北斗短报文终端在应急消防通信场景中的应用

在应对自然灾害和紧急情况时&#xff0c;北斗三号短报文终端以其全球覆盖、实时通信和精准定位的能力&#xff0c;成为应急消防通信的得力助手。它不仅能够在地面通信中断的极端条件下保障信息传递的畅通&#xff0c;还能提供精准的位置信息&#xff0c;为救援行动提供有力支持…...

Java跳动爱心代码

1.计算爱心曲线上的点的公式 计算爱心曲线上的点的公式通常基于参数方程。以下是两种常见的参数方程表示方法&#xff0c;用于绘制爱心曲线&#xff1a; 1.1基于 (x, y) 坐标的参数方程 x a * (2 * cos(θ) - sin(θ))^3 y a * (2 * sin(θ) - cos(θ))^3 其中&#xff…...

Swift Combine — Operators(常用Filtering类操作符介绍)

目录 filter(_: )tryFilter(_: )compactMap(_: )tryCompactMap(_: )removeDuplicates()first(where:)last(where:) Combine中对 Publisher的值进行操作的方法称为 Operator&#xff08;操作符&#xff09;。 Combine中的 Operator通常会生成一个 Publisher&#xff0c;该 …...

Windows11+CUDA12.0+RTX4090如何配置安装Tensorflow2-GPU环境?

1 引言 电脑配置 Windows 11 cuda 12.0 RTX4090 由于tensorflow2官网已经不支持cuda11以上的版本了&#xff0c;配置cuda和tensorflow可以通过以下步骤配置实现。 2 步骤 &#xff08;1&#xff09;创建conda环境并安装cuda和cudnn&#xff0c;以及安装tensorflow2.10 con…...

韩顺平0基础学Java——第27天

p548-568 明天开始坦克大战 Entry 昨天没搞明白的Map、Entry、EntrySet&#xff1a;//GPT教的 Map 和 Entry 的关系 1.Map 接口&#xff1a;它定义了一些方法来操作键值对集合。常用的实现类有 HashMap、TreeMap 等。 2. Entry接口&#xff1a;Entry 是 Map 接口的一个嵌…...

YesPMP探索Python在生活中的应用,助力提升开发效率

Python是一种简单易学、高效强大的编程语言&#xff0c;正变成越来越多人选择的热门技能。学习Python不仅可以提供更多就业机会&#xff0c;还能让自己在职场更加有竞争力&#xff0c;那可以去哪里拓展自己的技能呢&#xff1f; YesPMP平台 为熟练掌握Python语言的程序员提供了…...

TikTok账号运营:静态住宅IP为什么可以防封?

静态住宅IP代理服务是一种提供稳定、静态IP地址并可隐藏用户真实IP地址的网络代理服务。此类代理服务通常使用高速光纤网络来提供稳定、高速的互联网体验。与动态IP代理相比&#xff0c;静态住宅IP代理的IP地址更稳定&#xff0c;被封的可能性更小&#xff0c;因此更受用户欢迎…...

linux系统宝塔服务器temp文件夹里总是被上传病毒php脚本

目录 简介 上传过程 修复上传漏洞 tmp文件夹总是被上传病毒文件如下图: 简介 服务器时不时的会发送短信说你服务器有病毒, 找到了这个tmp文件, 删除了之后又有了。 确实是有很多人就这么无聊, 每天都攻击你的服务器。 找了很久的原因, 网上也提供了一大堆方法,…...

HTML+CSS+PHP实现网页留言板功能(需要创建数据库)

话说前头&#xff0c;我这方面很菜滴。这是我网页作业的一部分。 1.body部分效果展示&#xff08;不包括footer&#xff09; 2、代码 2.1 leaving.php&#xff08;看到的网页&#xff09; <!DOCTYPE html> <html lang"en"> <head> <met…...

【谷歌】实用的搜索技巧

1、使用正确的谷歌网址 我们知道https://www.google.com是谷歌的网址。但根据国家,用户可能会被重定向到 google.fr(法国)或google.co.in(印度)。 最主要的URL——google.com是为美国用户准备的(或是针对全世界所有用户的唯一URL))。当你在谷歌上搜索时,了解这一点是相…...

打造完美启动页:关键策略与设计技巧

启动页&#xff08;Splash Screen&#xff09;设计是指在应用程序启动时&#xff0c;首先展示给用户的界面设计。这个界面通常在应用加载或初始化期间显示&#xff0c;其主要目的是为用户提供一个视觉缓冲&#xff0c;展示品牌标识&#xff0c;并减少用户在等待过程中的焦虑感。…...

电子书(chm)-加载JS--CS上线

免责声明: 本文仅做技术交流与学习... 目录 cs--web投递 html(js)代码 html生成chm工具--EasyCHM 1-选择powershell 模式 生成 2-选择bitsadmin模式生成 chm反编译成html cs--web投递 cs配置监听器--->攻击---->web投递---> 端口选择没占用的, URL路径到时候会在…...

理解HTTP请求格式

HTTP概念 HTTP全称HyperTextTransfer Protocol(超文本传输协议)是一种用于分布式、协作式和超媒体信息系统的应用层协议&#xff1b;HTTP是一个客户端&#xff08;用户&#xff09;和服务端&#xff08;网站&#xff09;之间请求和响应的标准。 HTTP 协议是以 ASCII 码传输&…...

差分数组汇总

本文涉及知识点 算法与数据结构汇总 差分数组 令 a[i] ∑ j : 0 i v D i f f [ i ] \sum_{j:0}^{i}vDiff[i] ∑j:0i​vDiff[i] 如果 vDiff[i1]&#xff0c;则a[i1…]全部 如果vDiff[i2]–,则a[i2…]全部–。 令11 < i2 &#xff0c;则&#xff1a; { a [ i ] 不变&…...

SpringBoot | 实现邮件发送

运行环境&#xff1a; IntelliJ IDEA 2022.2.5 (Ultimate Edition) (注意&#xff1a;idea必须在2021版本以上&#xff09;JDK17 项目目录&#xff1a; 该项目分为pojo,service,controller,utils四个部分&#xff0c; 在pojo层里面写实体内容&#xff08;发邮件需要的发件人邮…...

spring boot接入nacos 配置中心

再接入nacos配置中心时&#xff0c;需要确认几点&#xff1a; 1. spring boot 版本 (spring boot 2.x ) 2. nacos 配置中心 服务端 版本 (1.1.4) 3. nacos client 客户端版本 (1.1.4) 方式一 1. 启动 nacos 服务端&#xff0c;这里不做解释 在配置中心中加入几个配置 2. 在…...

产品应用 | 小盒子跑大模型!英码科技基于算能BM1684X平台实现大模型私有化部署

当前&#xff0c;在人工智能领域&#xff0c;大模型在丰富人工智能应用场景中扮演着重要的角色&#xff0c;经过不断的探索&#xff0c;大模型进入到落地的阶段。而大模型在落地过程中面临两大关键难题&#xff1a;对庞大计算资源的需求和对数据隐私与安全的考量。为应对这些挑…...

uniapp中u-input点击事件失效

当给u-input设置了disabled/readonly属性后&#xff0c;pc浏览器中点击事件失效&#xff0c;但是app/移动端h5中却仍有效 解决办法 给外边包上一个盒子设置点击事件&#xff0c;给input加上css属性&#xff1a;pointer-events&#xff1a;none pointer-events CSS 属性指定在什…...

后进先出(LIFO)详解

LIFO 是 Last In, First Out 的缩写&#xff0c;中文译为后进先出。这是一种数据结构的工作原则&#xff0c;类似于一摞盘子或一叠书本&#xff1a; 最后放进去的元素最先出来 -想象往筒状容器里放盘子&#xff1a; &#xff08;1&#xff09;你放进的最后一个盘子&#xff08…...

应用升级/灾备测试时使用guarantee 闪回点迅速回退

1.场景 应用要升级,当升级失败时,数据库回退到升级前. 要测试系统,测试完成后,数据库要回退到测试前。 相对于RMAN恢复需要很长时间&#xff0c; 数据库闪回只需要几分钟。 2.技术实现 数据库设置 2个db_recovery参数 创建guarantee闪回点&#xff0c;不需要开启数据库闪回。…...

RocketMQ延迟消息机制

两种延迟消息 RocketMQ中提供了两种延迟消息机制 指定固定的延迟级别 通过在Message中设定一个MessageDelayLevel参数&#xff0c;对应18个预设的延迟级别指定时间点的延迟级别 通过在Message中设定一个DeliverTimeMS指定一个Long类型表示的具体时间点。到了时间点后&#xf…...

Leetcode 3576. Transform Array to All Equal Elements

Leetcode 3576. Transform Array to All Equal Elements 1. 解题思路2. 代码实现 题目链接&#xff1a;3576. Transform Array to All Equal Elements 1. 解题思路 这一题思路上就是分别考察一下是否能将其转化为全1或者全-1数组即可。 至于每一种情况是否可以达到&#xf…...

JVM暂停(Stop-The-World,STW)的原因分类及对应排查方案

JVM暂停(Stop-The-World,STW)的完整原因分类及对应排查方案,结合JVM运行机制和常见故障场景整理而成: 一、GC相关暂停​​ 1. ​​安全点(Safepoint)阻塞​​ ​​现象​​:JVM暂停但无GC日志,日志显示No GCs detected。​​原因​​:JVM等待所有线程进入安全点(如…...

CMake控制VS2022项目文件分组

我们可以通过 CMake 控制源文件的组织结构,使它们在 VS 解决方案资源管理器中以“组”(Filter)的形式进行分类展示。 🎯 目标 通过 CMake 脚本将 .cpp、.h 等源文件分组显示在 Visual Studio 2022 的解决方案资源管理器中。 ✅ 支持的方法汇总(共4种) 方法描述是否推荐…...

力扣-35.搜索插入位置

题目描述 给定一个排序数组和一个目标值&#xff0c;在数组中找到目标值&#xff0c;并返回其索引。如果目标值不存在于数组中&#xff0c;返回它将会被按顺序插入的位置。 请必须使用时间复杂度为 O(log n) 的算法。 class Solution {public int searchInsert(int[] nums, …...

蓝桥杯 冶炼金属

原题目链接 &#x1f527; 冶炼金属转换率推测题解 &#x1f4dc; 原题描述 小蓝有一个神奇的炉子用于将普通金属 O O O 冶炼成为一种特殊金属 X X X。这个炉子有一个属性叫转换率 V V V&#xff0c;是一个正整数&#xff0c;表示每 V V V 个普通金属 O O O 可以冶炼出 …...

保姆级教程:在无网络无显卡的Windows电脑的vscode本地部署deepseek

文章目录 1 前言2 部署流程2.1 准备工作2.2 Ollama2.2.1 使用有网络的电脑下载Ollama2.2.2 安装Ollama&#xff08;有网络的电脑&#xff09;2.2.3 安装Ollama&#xff08;无网络的电脑&#xff09;2.2.4 安装验证2.2.5 修改大模型安装位置2.2.6 下载Deepseek模型 2.3 将deepse…...

【Go语言基础【12】】指针:声明、取地址、解引用

文章目录 零、概述&#xff1a;指针 vs. 引用&#xff08;类比其他语言&#xff09;一、指针基础概念二、指针声明与初始化三、指针操作符1. &&#xff1a;取地址&#xff08;拿到内存地址&#xff09;2. *&#xff1a;解引用&#xff08;拿到值&#xff09; 四、空指针&am…...