通过进程协作显示图像-C#
前言
如果一个软件比较复杂或者某些情况下需要拆解,可以考试将软件分解成两个或多个进程,但常规的消息传递又不能完全够用,使用消息+共享内存,实现图像传递,当然性能这个方面我并没有测试,仅是一种解决思路吧。
一、效果展示
1、调用方

2、被调用方

二、实现代码
1、主调打开调用进程
主要是为了拿到Handle,为发送消息函数提供操作句柄。

2、创建共享内存
/// <summary>/// 创建共享内存/// </summary>/// <returns>0=创建成功;1=创建共享体失败;2=打开失败;3=印射失败; 4=共享内存命名错误</returns>public int CreateMemory(){if (MemSize <= 0) MemSize = 0x00800000;if (ShareName.Length > 0){//创建内存共享体(INVALID_HANDLE_VALUE)m_hSharedMemoryFile = CreateFileMapping(INVALID_HANDLE_VALUE, IntPtr.Zero, (uint)PAGE_READWRITE, 0, (uint)MemSize, ShareName);if (m_hSharedMemoryFile == IntPtr.Zero){m_bAlreadyExist = false;m_bInit = false;MemPtr = IntPtr.Zero;return 1; //创建共享体失败}else{if (GetLastError() == ERROR_ALREADY_EXISTS) //已经创建{m_bAlreadyExist = true;CloseHandle(m_hSharedMemoryFile);m_hSharedMemoryFile = OpenFileMapping(FILE_MAP_ALL_ACCESS, false, ShareName);if (m_hSharedMemoryFile == null){MemPtr = IntPtr.Zero;return 2;//打开共享内存失败}}else //新创建{m_bAlreadyExist = false;}}//创建内存映射m_rwData = MapViewOfFile(m_hSharedMemoryFile, FILE_MAP_ALL_ACCESS, 0, 0, (uint)MemSize);if (m_rwData == IntPtr.Zero){m_bInit = false;CloseHandle(m_hSharedMemoryFile);MemPtr = IntPtr.Zero;return 3; //创建内存映射失败}else{m_bInit = true;MemPtr = m_rwData;}}else{return 4; //参数错误}return 0; //创建成功}
3、读取本地图像并写图像数据到共享内存中
MyAlgoProcessNet.HImage hImage = new MyAlgoProcessNet.HImage(fileName);IntPtr prt = hImage.GetImagePointer1(out string type, out imageData.Widht, out imageData.Height);imageData.dataLength = imageData.Widht * imageData.Height;byte[] datas = new byte[imageData.dataLength];Marshal.Copy(prt, datas, 0, imageData.dataLength);int pos = Marshal.SizeOf(imageData);share1.WriteToMemory(imageData);//写共享内存if (share1.WriteBytes(datas, pos + 1) == 0){WriteMsg("share1写入共享内存成功");}else{WriteMsg("share1写入共享内存失败!!");}public int WriteBytes(byte[] datas, int pos = -1){if (IntPtr.Zero == MemPtr){return -1;}if (pos == -1){Marshal.Copy(datas, 0, MemPtr, datas.Length);}else{IntPtr offPtr = IntPtr.Add(MemPtr, pos);Marshal.Copy(datas, 0, offPtr, datas.Length);}return 0;}
4、通知读取数据
private void SendMsg2(string msg)
{// 获取目标进程句柄IntPtr hWnd = process.MainWindowHandle;// 封装消息byte[] sarr = System.Text.Encoding.Default.GetBytes(msg);int len = sarr.Length;COPYDATASTRUCT cds2;cds2.dwData = (IntPtr)0;cds2.cbData = len + 1;cds2.lpData = msg;// 发送消息WriteMsg(msg + " Start");SendMessage(hWnd, WM_COPYDATA, IntPtr.Zero, ref cds2);WriteMsg(msg + " End");
}
5、被调用方关联消息处理函数
protected override void OnSourceInitialized(EventArgs e){base.OnSourceInitialized(e);HwndSource hwndSource = PresentationSource.FromVisual(this) as HwndSource;if (hwndSource != null){IntPtr handle = hwndSource.Handle;hwndSource.AddHook(new HwndSourceHook(WndProc));}}
6、被调用方处理图像数据
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled){if (msg == WM_COPYDATA){WriteInfo(1, "WndProc Start");COPYDATASTRUCT cds = (COPYDATASTRUCT)Marshal.PtrToStructure(lParam,typeof(COPYDATASTRUCT)); // 接收封装的消息string rece = cds.lpData; // 获取消息内容// 自定义行为// Console.WriteLine(rece);if (rece == "Read"){Task.Run(() =>{//读共享内存// datastruct = (MemoryClass)shareMemory.ReadFromMemory(typeof(MemoryClass));// WriteInfo(1, $"读取数据:{datastruct.bianliang1},{datastruct.bianliang2},{datastruct.bianliang3}");imageData = (ImageData)shareMemory.ReadFromMemory(typeof(ImageData));int ShareSize = Marshal.SizeOf(imageData);byte[] datas = shareMemory.ReadByteFromMemory(imageData.dataLength, ShareSize + 1);HImage hImage = new HImage();using (PinnedObject pinnedObject = new PinnedObject(datas)){hImage.GenImage1("byte", imageData.Widht, imageData.Height, pinnedObject.Pointer);}// hImage.GenImage1(imageData.DataType, imageData.Widht, imageData.Height, imageData.dataPrt);ImgControl.HalconWindow.AttachBackgroundToWindow(hImage);WriteInfo(1, "图像处理完成");});}// Thread.Sleep(2000);WriteInfo(2, rece);if (rece.Equals("Close")){this.Close();}}return hwnd;}
7、共享内存操作
internal class ShareMemory{[DllImport("user32.dll", CharSet = CharSet.Auto)]public static extern IntPtr SendMessage(IntPtr hWnd, int Msg, int wParam, IntPtr lParam);[DllImport("Kernel32.dll", CharSet = CharSet.Auto)]public static extern IntPtr CreateFileMapping(int hFile, IntPtr lpAttributes, uint flProtect, uint dwMaxSizeHi, uint dwMaxSizeLow, string lpName);[DllImport("Kernel32.dll", CharSet = CharSet.Auto)]public static extern IntPtr OpenFileMapping(int dwDesiredAccess, [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, string lpName);[DllImport("Kernel32.dll", CharSet = CharSet.Auto)]public static extern IntPtr MapViewOfFile(IntPtr hFileMapping, uint dwDesiredAccess, uint dwFileOffsetHigh, uint dwFileOffsetLow, uint dwNumberOfBytesToMap);[DllImport("Kernel32.dll", CharSet = CharSet.Auto)]public static extern bool UnmapViewOfFile(IntPtr pvBaseAddress);[DllImport("Kernel32.dll", CharSet = CharSet.Auto)]public static extern bool CloseHandle(IntPtr handle);[DllImport("kernel32", EntryPoint = "GetLastError")]public static extern int GetLastError();private const int INVALID_HANDLE_VALUE = -1;private const int ERROR_ALREADY_EXISTS = 0xB7;//183private const int PAGE_READWRITE = 0x04;private const int FILE_MAP_ALL_ACCESS = 0x0002 | 0x0004;private const int FILE_MAP_READ = 0x0004;private const int FILE_MAP_WRITE = 0x0002;private IntPtr m_hSharedMemoryFile = IntPtr.Zero;private IntPtr m_rwData = IntPtr.Zero;private bool m_bAlreadyExist = false;private bool m_bInit = false;private string ShareName { get; set; } //共享内存的名字private long MemSize { get; set; }//共享内存大小private IntPtr MemPtr { get; set; }//共享内存印射地址/// <summary>/// 共享内存初始化/// </summary>/// <param name="MemName">共享内存名字</param>/// <param name="MemSize">共享内存大小</param>public ShareMemory(string MemName, long Size){ShareName = MemName;MemSize = Size;MemPtr = IntPtr.Zero;m_bInit = false;m_bAlreadyExist = false;m_rwData = IntPtr.Zero;m_hSharedMemoryFile = IntPtr.Zero;}~ShareMemory(){ShareMemoryClose();}/// <summary>/// 创建共享内存/// </summary>/// <returns>0=创建成功;1=创建共享体失败;2=打开失败;3=印射失败; 4=共享内存命名错误</returns>public int CreateMemory(){if (MemSize <= 0) MemSize = 0x00800000;if (ShareName.Length > 0){//创建内存共享体(INVALID_HANDLE_VALUE)m_hSharedMemoryFile = CreateFileMapping(INVALID_HANDLE_VALUE, IntPtr.Zero, (uint)PAGE_READWRITE, 0, (uint)MemSize, ShareName);if (m_hSharedMemoryFile == IntPtr.Zero){m_bAlreadyExist = false;m_bInit = false;MemPtr = IntPtr.Zero;return 1; //创建共享体失败}else{if (GetLastError() == ERROR_ALREADY_EXISTS) //已经创建{m_bAlreadyExist = true;CloseHandle(m_hSharedMemoryFile);m_hSharedMemoryFile = OpenFileMapping(FILE_MAP_ALL_ACCESS, false, ShareName);if (m_hSharedMemoryFile == null){MemPtr = IntPtr.Zero;return 2;//打开共享内存失败}}else //新创建{m_bAlreadyExist = false;}}//创建内存映射m_rwData = MapViewOfFile(m_hSharedMemoryFile, FILE_MAP_ALL_ACCESS, 0, 0, (uint)MemSize);if (m_rwData == IntPtr.Zero){m_bInit = false;CloseHandle(m_hSharedMemoryFile);MemPtr = IntPtr.Zero;return 3; //创建内存映射失败}else{m_bInit = true;MemPtr = m_rwData;}}else{return 4; //参数错误}return 0; //创建成功}public byte[] ReadByteFromMemory(int dataLength, int pos = -1){if (IntPtr.Zero == MemPtr){return new byte[0];}byte[] datas = new byte[dataLength];if (pos == -1){Marshal.Copy(MemPtr, datas, 0, dataLength);}else{IntPtr offPtr = IntPtr.Add(MemPtr, pos);Marshal.Copy(offPtr, datas, 0, dataLength);}return datas;}/// <summary>/// 读取共享内存并返回到类/// </summary>/// <param name="type">读取的类型</param>/// <returns>读取的数据</returns>public Object ReadFromMemory(Type type){if (IntPtr.Zero == MemPtr){return null;}Object obj = Marshal.PtrToStructure(MemPtr, type);return obj;}/// <summary>/// 读取类并写入共享内存/// </summary>/// <param name="obj">需要读取的类(结构体)</param>/// <returns>返回0表示写入成功,返回-1表示写入失败</returns>public int WriteToMemory(Object obj){if (IntPtr.Zero == MemPtr){return -1;}Marshal.StructureToPtr(obj, MemPtr, false);return 0;}/// <summary>/// 关闭共享内存(解除印射,关闭句柄)/// </summary>public void ShareMemoryClose(){if (m_bInit){UnmapViewOfFile(m_rwData);CloseHandle(m_hSharedMemoryFile);m_bInit = false;}}/// <summary>/// 获取共享内存印射地址/// </summary>/// <returns></returns>public IntPtr GetPtr(){return MemPtr;}/// <summary>/// 获取文件句柄/// </summary>/// <returns></returns>public IntPtr GetFileMapPtr(){return m_hSharedMemoryFile;}/// <summary>/// 获取共享内存大小/// </summary>/// <returns></returns>public long GetSize(){return MemSize;}/// <summary>/// 获取共享内存名字/// </summary>/// <returns></returns>public string GetName(){return ShareName;}}
相关文章:
通过进程协作显示图像-C#
前言 如果一个软件比较复杂或者某些情况下需要拆解,可以考试将软件分解成两个或多个进程,但常规的消息传递又不能完全够用,使用消息共享内存,实现图像传递,当然性能这个方面我并没有测试,仅是一种解决思路…...
LangChain链与记忆处理[10]:四种基础内置链、四种文档处理链,以及链的自定义和五种运行方式,让你的大模型更加智能
LangChain链与记忆处理[10]:四种基础内置链、四种文档处理链,以及链的自定义和五种运行方式,让你的大模型更加智能 参考文章可以使用国产LLM进行下述项目复现: 初识langchain[1]:Langchain实战教学,利用qwen2.1与GLM-4大模型构建智能解决方案[含Agent、tavily面向AI搜索…...
京东发行稳定币的背后
加密市场很热,京东也要来分一杯羹? 7月24日,据财联社报道,京东科技旗下的京东币链科技 ( 香港 ) 将在香港发行与港元 1:1锚定的加密货币稳定币,在市场上掀起广泛热议。 由于众所周知的监管原因,国内大厂在早…...
CF1995C Squaring 题解
思路详解: 请注意,本题解用到了非整数计算,也就是说性能可能不如整数运算,但是易于实现,追求最优解的大佬不建议观看本题解。 这个题看似简单,但是由于涉及到了平方操作,不用高精度根本存不下&…...
动态规划之路径问题
动态规划算法介绍 基本原理和解题步骤 针对于动态规划的题型,一般会借助一个 dp 表,然后确定这个表中应该填入什么内容,最终直接返回表中的某一个位置的元素。 细分可以分为以下几个步骤: 创建 dp 表以及确定 dp 表中所要填写位…...
如何优化你的TikTok短视频账号运营策略?
在运营TikTok账号时,采取正确的策略至关重要,这些策略能够帮助你提升账号的质量和吸引力。 适度使用互粉互赞 避免过度依赖互粉互赞,因为这可能会限制你的内容在更广泛的观众中传播。虽然互粉互赞可以增加曝光,但过度使用可能导…...
mysql的唯一索引和普通索引有什么区别
在MySQL中,唯一索引(UNIQUE Index)和普通索引(普通索引,也称为非唯一索引)有一些关键的区别。以下是它们的比较以及性能分析: 唯一索引与普通索引的区别 唯一性: 唯一索引ÿ…...
Scrapy框架在处理大规模数据抓取时有哪些优化技巧?
在使用Scrapy框架处理大规模数据抓取时,优化技巧至关重要,可以显著提高爬虫的性能和效率。以下是一些实用的优化技巧: 1. 并发请求 增加并发请求的数量可以提高爬虫的响应速度和数据抓取效率。可以通过设置CONCURRENT_REQUESTS参数来调整。…...
私有化低代码平台的优势:赋能业务用户,重塑IT自主权
随着数字化转型在全球范围内的不断推进,企业面临着快速响应市场变化和提高内部运营效率的双重挑战。在这种背景下,低代码平台逐渐成为企业实现敏捷开发和快速迭代的重要工具。私有化低代码平台作为一种更安全、可控的解决方案,越来越受到企业…...
SAP BW系统表分享第一弹
有时候想要查看BW系统中存在了多少的表时,包含SAP以及自建表,这个时候我们怎么去找呢? 不要慌,BW系统中也有其对应系统表来存储表对应的信息的,存储所有表信息的是DD02V或者DD02VV,我比较推荐使用DD02VV&a…...
详解工厂模式与抽象工厂模式有什么区别?【图解+代码】
目录 工厂模式,抽象工厂模式是什么? 两种设计模式的流程: 1、工厂模式 2、抽象工厂模式 两种模式的对比 共同点: 不同点: 总结 工厂模式,抽象工厂模式是什么? 我已经具体的写了这两种模…...
zeroice做json字符串转为struct,支持结构体嵌套
1 zeroice Properties 基础类型 字典 数组 不支持复杂结构 2 zeroice没有内置反射 3 java反射 slice2java.exe ice转java类 java类转json字符串 json字符串组织测试json文件 jsonobj转为vector jar包onjvm运行 pub到broker 4 c反射from_json.cpp slice2cpp.exe ice转.h 注…...
Linux笔记 --- 内存管理
在程序中我们访问的内存地址都是从物理内存上映射而来的虚拟地址,假设我们使用的计算机实际物理内存(PM)只有1GB,而Linux中执行着三个进程,Linux会将PM中的某段内存映射成三段4G大小相同的虚拟内存(VM&…...
树莓派通过webRTC进行视频流传输到公网
为了实现树莓派和浏览器之间的视频流传输,你需要在公网服务器上运行 Node.js 的信令服务器,同时在树莓派上运行 Node.js 客户端代码。以下是具体的步骤和说明: 1. 公网服务器 安装 Node.js:在公网服务器上,你需要安装…...
【数据结构与算法】循环队列
循环队列 一.循环队列的引入二.循环队列的原理三.循环队列判断是否为满或空1.是否为空2.是否为满 四.循环队列入队五.循环队列出队六.循环队列的遍历七.循环队列获取长度八.总结 一.循环队列的引入 还记得我们顺序队列的删除元素嘛,我们有两种方式,一种是将数组要删除元素后面…...
为什么推荐使用@RequiredArgsConstructor代替@Autowired?
首先说一下前提: 项目中已经使用了Lombok,否则添加 Lombok 可能会增加项目的复杂度和构建时间。如果依赖项是可选的或可能在运行时改变,则使用字段注入或 setter 注入可能更为合适。 正文: 在 Spring 框架中,Autowir…...
ARM系列运行异常排查
一、断点指令BKPT BKPT指令产生软件断点中断,可用于程序的调试。它使处理器停止执行正常指令(使处理器中止预取指)而进入相应的调试程序。 BKPT指令的格式为:BKPT 16位的立即数 二、使用BKPT进行软件异常定位 假设异常发生后…...
Hive3:库操作常用语句
1、创建库 create database if not exists myhive;2、选择库 use myhive;3、查看当前选择的库 SELECT current_database();4、查看库详细信息 desc database myhive;可以查看数据文件在hdfs集群中的存储位置 5、创建库时制定hdfs的存储位置 create database myhive2 …...
C语言实现:C51单片机驱动LCD屏幕显示字符串(Proteus+Keil)
在Proteus中绘制电路原理图 我使用的版本是Protues8.16 ,Protues特别擅长仿真单片机及其外围设备,支持多种类型的微控制器,如8051、HC11、PIC、AVR、ARM、MSP430等,也可以设计pcb板,还能3D建模 1.新建工程 在 Start 栏中点击 …...
暄桐好作业之《临沈周〈东庄图册〉局部》
暄桐是一间传统美学教育教室,创办于2011年,林曦是创办人和授课老师,教授以书法为主的传统文化和技艺,皆在以书法为起点,亲近中国传统之美,以实践和所得,滋养当下生活。 其中“暄桐好作…...
MongoDB学习和应用(高效的非关系型数据库)
一丶 MongoDB简介 对于社交类软件的功能,我们需要对它的功能特点进行分析: 数据量会随着用户数增大而增大读多写少价值较低非好友看不到其动态信息地理位置的查询… 针对以上特点进行分析各大存储工具: mysql:关系型数据库&am…...
DAY 47
三、通道注意力 3.1 通道注意力的定义 # 新增:通道注意力模块(SE模块) class ChannelAttention(nn.Module):"""通道注意力模块(Squeeze-and-Excitation)"""def __init__(self, in_channels, reduction_rat…...
【第二十一章 SDIO接口(SDIO)】
第二十一章 SDIO接口 目录 第二十一章 SDIO接口(SDIO) 1 SDIO 主要功能 2 SDIO 总线拓扑 3 SDIO 功能描述 3.1 SDIO 适配器 3.2 SDIOAHB 接口 4 卡功能描述 4.1 卡识别模式 4.2 卡复位 4.3 操作电压范围确认 4.4 卡识别过程 4.5 写数据块 4.6 读数据块 4.7 数据流…...
uniapp微信小程序视频实时流+pc端预览方案
方案类型技术实现是否免费优点缺点适用场景延迟范围开发复杂度WebSocket图片帧定时拍照Base64传输✅ 完全免费无需服务器 纯前端实现高延迟高流量 帧率极低个人demo测试 超低频监控500ms-2s⭐⭐RTMP推流TRTC/即构SDK推流❌ 付费方案 (部分有免费额度&#x…...
零基础在实践中学习网络安全-皮卡丘靶场(第九期-Unsafe Fileupload模块)(yakit方式)
本期内容并不是很难,相信大家会学的很愉快,当然对于有后端基础的朋友来说,本期内容更加容易了解,当然没有基础的也别担心,本期内容会详细解释有关内容 本期用到的软件:yakit(因为经过之前好多期…...
力扣-35.搜索插入位置
题目描述 给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。 请必须使用时间复杂度为 O(log n) 的算法。 class Solution {public int searchInsert(int[] nums, …...
CVE-2020-17519源码分析与漏洞复现(Flink 任意文件读取)
漏洞概览 漏洞名称:Apache Flink REST API 任意文件读取漏洞CVE编号:CVE-2020-17519CVSS评分:7.5影响版本:Apache Flink 1.11.0、1.11.1、1.11.2修复版本:≥ 1.11.3 或 ≥ 1.12.0漏洞类型:路径遍历&#x…...
【Linux】Linux 系统默认的目录及作用说明
博主介绍:✌全网粉丝23W,CSDN博客专家、Java领域优质创作者,掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域✌ 技术范围:SpringBoot、SpringCloud、Vue、SSM、HTML、Nodejs、Python、MySQL、PostgreSQL、大数据、物…...
windows系统MySQL安装文档
概览:本文讨论了MySQL的安装、使用过程中涉及的解压、配置、初始化、注册服务、启动、修改密码、登录、退出以及卸载等相关内容,为学习者提供全面的操作指导。关键要点包括: 解压 :下载完成后解压压缩包,得到MySQL 8.…...
学习一下用鸿蒙DevEco Studio HarmonyOS5实现百度地图
在鸿蒙(HarmonyOS5)中集成百度地图,可以通过以下步骤和技术方案实现。结合鸿蒙的分布式能力和百度地图的API,可以构建跨设备的定位、导航和地图展示功能。 1. 鸿蒙环境准备 开发工具:下载安装 De…...
