如何实现win9X进程间数据通讯技术

[YIUI付费插件] 超级循环列表yiuisuperscroll 本文介绍基于YIUI框架实现循环列表(LoopListView2)的完整流程:在Scroll Rect上挂载LoopListView2并配置预制体,为Item添加Click同步事件;通过ServerListPanelComponent与ServerInfoItemComponent配合,使用YIUISuperScrollListRenderer和YIUISuperScrollListOnClick实现数据渲染与点击响应,支持动态刷新列表、选中状态管理及服务器信息绑定,高效构建可交互的滚动列表界面。 阅读详情

1、引言
  在Windows程序中,各个进程之间常常需要交换数据,进行数据通讯。WIN32 API提供了许多函数使我们能够方便高效地进行进程间的通讯,通过这些函数我们可以控制不同进程间的数据交换,就如同在WIN16中对本地进程进行读写操作一样。
  典型的WIN16两进程可以通过共享内存来进行数据交换:

(1)进程A将GlobalAlloc(GMEM_SHARE...)API分配一定长度的内存;(2)进程A将GlobalAlloc函数返回的句柄传递给进程B(通过一个登录消息);(3)进程B对这个句柄调用GlobalLock函数,并利用GlobalLock函数返回的指针访问数据。这种方法在WIN32中可能失败,这是因为GlobalLock函数返回指向的是进程A的内存,由于进程使用的是虚拟地址而非实际物理地址,因此这一指针仅与A进程有关,而于B进程无关。
  本文探讨了几种WIN32下进程之间通讯的几种实现方法,读者可以使用不同的方
法以达到程序运行高效可靠的目的。
  2、Windows95中进程的内存空间管理
  WIN32进程间通讯与Windows95的内存管理有密切关系,理解Windows95的内存管理对我们如下的程序设计将会有很大的帮助,下面我们讨论以下Windows95中进程的内存空间管理。
  在WIN16下,所有Windows应用程序共享单一地址,任何进程都能够对这一空间中属于共享单一的地址空间和属于其他进程的内存进行读写操作,甚至可以存取操作系统本身的数据,这样就可能破坏其他程序的数据段代码。
  在WIN32下,每个进程都有自己的地址空间,一个WIN32进程不能存取另一个地
址的私有数据,两个进程可以用具有相同值的指针寻址,但所读写的只是它们各自
的数据,这样就减少了进程之间的相互干扰。另一方面,每个WIN32进程拥有4GB的
地址空间,但并不代表它真正拥有4GB的实际物理内存,而只是操作系统利用CPU的
内存分配功能提供的虚拟地址空间。在一般情况下,绝大多数虚拟地址并没有物理
内存与它对应,在真正可以使用这些地址空间之前,还要由操作系统提供实际的物
理内存(这个过程叫“提交”commit)。在不同的情况下,系统提交的
物理内存是不同的,可能是RAM,也可能是硬盘模拟的虚拟内存。
  3、WIN32中进程间的通讯
  在Windows 95中,为实现进程间平等的数据交换,用户可以有如下几种选择:
  * 使用内存映射文件
  * 通过共享内存DLL共享内存
  * 向另一进程发送WM_COPYDATA消息
  * 调用ReadProcessMemory以及WriteProcessMemory函数,用户可以发送由
GlobalLock(GMEM_SHARE,...)函数调用提取的句柄、GlobalLock函数返回的指针以
及VirtualAlloc函数返回的指针。
  3.1、利用内存映射文件实现WIN32进程间的通讯
  Windows95中的内存映射文件的机制为我们高效地操作文件提供了一种途径,
它允许我们在WIN32进程中保留一段内存区域,把目标文件映射到这段虚拟内存中。
在程序实现中必须考虑各进程之间的同步。具体实现步骤如下:
  首先我们在发送数据的进程中需要通过调用内存映射API函数CreateFileMapping
创建一个有名的共享内存:
  HANDLE CreateFileMapping(
  HANDLE hFile, // 映射文件的句柄,
  //设为0xFFFFFFFF以创建一个进程间共享的对象
  LPSECURITY_ATTRIBUTES lpFileMappingAttributes, // 安全属性
  DWORD flProtect, // 保护方式
  DWORD dwMaximumSizeHigh, //对象的大小
  DWORD dwMaximumSizeLow,
  LPCTSTR lpName // 必须为映射文件命名
  );
  与虚拟内存类似,保护方式可以是PAGE_READONLY或是PAGE_READWRITE。如果多进程都对同一共享内存进行写访问,则必须保持相互间同步。映射文件还可以指定PAGE_WRITECOPY标志,可以保证其原始数据不会遭到破坏,同时允许其他进程在必要时自由地操作数据的拷贝。
  在创建文件映射对象后使用可以调用MapViewOfFile函数映射到本进程的地址空间内。
  下面说明创建一个名为MySharedMem的长度为4096字节的有名映射文件:
  HANDLE hMySharedMapFile=CreateFileMapping((HANDLE)0xFFFFFFFF),
  NULL,PAGE_READWRITE,0,0x1000,“MySharedMem”);
  并映射缓存区视图:
  LPSTR pszMySharedMapView=(LPSTR)MapViewOfFile(hMySharedMapFile,
  FILE_MAP_READ|FILE_MAP_WRITE,0,0,0);
  其他进程访问共享对象,需要获得对象名并调用OpenFileMapping函数。
  HANDLE hMySharedMapFile=OpenFileMapping(FILE_MAP_WRITE,
  FALSE,“MySharedMem");
  一旦其他进程获得映射对象的句柄,可以像创建进程那样调用MapViewOfFile函数来映射对象视图。用户可以使用该对象视图来进行数据读写操作,以达到数据通讯的目的。
  当用户进程结束使用共享内存后,调用UnmapViewOfFile函数以取消其地址空间内的视图:
  if (!UnmapViewOfFile(pszMySharedMap
  View))
  { AfxMessageBox(“could not unmap view of file"); }
  3.2、利用共享内存DLL
  共享数据DLL允许进程以类似于Windows 3.1 DLL共享数据的方式访问读写数据,多个进程都可以对该共享数据DLL进行数据操作,达到共享数据的目的。在WIN32中为建立共享内存,必须执行以下步骤:
  首先创建一个有名的数据区。这在Visual C++中是使用data_seg pragma宏。
使用data_seg pragma宏必须注意数据的初始化:
  #pragma data_seg(“MYSEC")
  char MySharedData[4096]={0};
  #pragma data_seg()
  然后在用户的DEF文件中为有名的数据区设定共享属性。
  LIBRARY TEST
  DATA READ WRITE
  SECTIONS
  .MYSEC READ WRITE SHARED
  这样每个附属于DLL的进程都将接受到属于自己的数据拷贝,一个进程的数据
变化并不会反映到其他进程的数据中。
  在DEF文件中适当地输出数据。以下的DEF文件项说明了如何以常数变量的形式
输出MySharedData。
  EXPORTS
  MySharedData CONSTANT
  最后在应用程序(进程)按外部变量引用共享数据。
  extern _export"C"{char * MySharedData[]}
  进程中使用该变量应注意间接引用。
  m_pStatic=(CEdit*)GetDlgItem(IDC_SHARED);
  m_pStatic->GetLine(0,*MySharedData,80);

3.3、用于传输只读数据的WM_COPYDATA
  传输只读数据可以使用Win32中的WM_COPYDATA消息。该消息的主要目的是允许在进程间传递只读数据。Windows95在通过WM_COPYDATA消息传递期间,不提供继承同步方式。SDK文档推荐用户使用SendMessage函数,接受方在数据拷贝完成前不返回,这样发送方就不可能删除和修改数据:
  SendMessage(hwnd,WM_COPYDATA,wPara
  m,lParam);
  其中wParam设置为包含数据的窗口的句柄。lParam指向一个COPYDATASTRUCT的结构:
  typedef struct tagCOPYDATASTRUCT{
  DWORD dwData;//用户定义数据
  DWORD cbData;//数据大小
  PVOID lpData;//指向数据的指针
  }COPYDATASTRUCT;
  该结构用来定义用户数据。
  3.4、直接调用ReadProcessMemory和WriteProcessMemory函数实现进程间通讯
  通过调用ReadProcessMemory以及WriteProcessMemory函数用户可以按类似与Windows3.1的方法实现进程间通讯,在发送进程中分配一块内存存放数据,可以调用GlobalAlloc或者VirtualAlloc函数实现:
  pApp→m_hGlobalHandle=GlobalAlloc(GMEM_SHARE,1024);
  可以得到指针地址:pApp→mpszGlobalHandlePtr=(LPSTR)GlobalLock(pApp→m_hGlobalHandle);
  在接收进程中要用到用户希望影响的进程的打开句柄。为了读写另一进程,应
按如下方式调用OpenProcess函数:
  HANDLE hTargetProcess=OpenProcess(
  STANDARD_RIGHTS_REQUIRED|
  PROCESS_VM_REDA|
  PROCESS_VM_WRITE|
  PROCESS_VM_OPERATION,//访问权限
  FALSE,//继承关系
  dwProcessID);//进程ID
  为保证OpenProcess函数调用成功,用户所影响的进程必须由上述标志创建。
  一旦用户获得一个进程的有效句柄,就可以调用ReadProcessMemory函数读取该
进程的内存:
  BOOL ReadProcessMemory(
  HANDLE hProcess, // 进程指针
  LPCVOID lpBaseAddress, // 数据块的首地址
  LPVOID lpBuffer, // 读取数据所需缓冲区
  DWORD cbRead, // 要读取的字节数
  LPDWORD lpNumberOfBytesRead
  );
  使用同样的句柄也可以写入该进程的内存:
  BOOL WriteProcessMemory(
  HANDLE hProcess, // 进程指针
  LPVOID lpBaseAddress, // 要写入的首地址
  LPVOID lpBuffer, // 缓冲区地址
  DWORD cbWrite, // 要写的字节数
  LPDWORD lpNumberOfBytesWritten
   );
  如下所示是读写另一进程的共享内存中的数据:
  ReadProcessMemory((HANDLE)hTargetProcess,(LPSTR)lpsz,m_strGlobal.GetBuffer(_MAX_FIELD),
  _MAX_FIELD,&cb);
  WriteProcessMemory((HANDLE)hTargetProcess,(LPSTR)lpsz,(LPSTR)STARS,
  m_strGlobal.GetLength(),&cb);
  4、进程之间的消息发送与接收
  在实际应用中进程之间需要发送和接收Windows消息来通知进程间相互通讯,
发送方发送通讯的消息以通知接收方,接收方在收到发送方的消息后就可以对内
存进行读写操作。
  我们在程序设计中采用Windows注册消息进行消息传递,首先在发送进程初始
化过程中进行消息注册:
  m_nMsgMapped=::RegisterWindowsMessage(“Mapped”);
  m_nMsgHandle=::RegisterWindowsMessage(“Handle”);
  m_nMsgShared=::RegisterWindowsMessage(“Shared”);
  在程序运行中向接收进程发送消息:
  CWnd* pWndRecv=FindWindow(lpClassName,“Receive”);
  pWndRecv→SendMessage(m_MsgMapped,0,0);
  pWndRecv→SendMessage(m_nMsgHandle,(UINT)GetCurrentProcessID(),(LONG)pApp→m_hGlobalHandle);
  pWndRecv→SendMessage(m_nMsgShared,0,0);
  可以按如下方式发送WM_COPYDATA消息:
  static COPYDATASTRUCT cds;//用户存放数据pWnd→SendMessage(WM_COPYDATA,NULL,(LONG)&cds);
  接收方进程初始化也必须进行消息注册:
  UNIT CRecvApp:: m_nMsgMapped=::RegisterWindowsMessage(“Mapped”);
  UNIT CRecvApp::m_nMsgHandle=::RegisterWindowsMessage(“Handle”);
  UNIT CRecvApp::m_nMsgShared=::RegisterWindowsMessage(“Shared”);
  同时映射消息函数如下:
  ON_REGISTERED_MASSAGE(CRecvApp::m_nMsgMapped,OnRegMsgMapped)
  ON_REGISTERED_MASSAGE(CRecvApp::m_nMsgHandle,OnRegMsgHandle)
  ON_REGISTERED_MASSAGE(CRecvApp::m_nMsgShared,OnRegMsgShared)
  有这些消息函数我们就可以采用上述技术实现接收进程中数据的读写操作了。
  5、结束语
  从以上分析中我们可以看出Windows9X的内存管理对进程之间的通讯有较为严
格的限制。这就确保了任何故障程序无法意外地写入用户的地址空间,而用户则可
根据实际情况灵活地进行进程间的数据通讯,从这一点上来讲Windows95增强了应用
程序的强壮性。
 

Qwen2.5-Omni实战:5分钟搞定多模态AI模型本地部署(含Thinker-Talker架构解析) 本文详细介绍了Qwen2.5-Omni多模态AI模型的本地部署流程,包括硬件配置、环境准备和实战应用开发。特别解析了其创新的Thinker-Talker架构,该架构通过TMRoPE位置编码实现跨模态同步处理,大幅提升多模态任务效率。5分钟即可完成部署,适合开发者快速实现文本、图像和音频的联合处理。 阅读详情

相关推荐

知识图谱_知识图谱 | 知识图谱做用户画像

导读:最近一直在思考怎么用知识图谱做推荐,但是目前能知道的内容都是基于路径的推荐和基于图特征的推荐,所以能不能换一个角度,探究一下用知识图谱怎么做用户画像,因为画像也是推荐系统重要的一部分。现在的知识图谱+推荐怎么做的传统的用户画像怎么做现在的知识图谱+推荐怎么做的?基于路径:可以理解成基于图谱的多路径召回,或者多路径推荐,然后根据路径的转移概率进行排序从而达到推荐的效果,基于路径比较适合简单的推...

weixin_28801659的博客 1460

如何用VC++和Visual Foxpro进行ActiveX数据通讯

如何用VC++和Visual Foxpro进行ActiveX数据通讯 粟利民 孙强 摘要 本文描述了如何利用自动服务器Active Automation,在VC++中与Visual Foxpro进行数据通讯的方法。通过自动服务器,圆满地解决了各种数据类型的交换问题。 关键词 VC++,Visual Foxpro,ActiveX Automation,数据通讯 在进行软件开发的过程中,如何在不同的编

蝈蝈俊.net 1828

TMC5130/TMC5160步进电机驱动芯片深度解析与工程实践

步进电机驱动芯片是精密运动控制系统的物理执行核心,其性能直接决定定位精度、运行噪声与系统鲁棒性。基于电流闭环控制与电压前馈调制的混合驱动原理,现代智能驱动芯片如TMC51X0系列实现了微步插补、堵转检测和片上运动规划等关键技术突破。这类芯片通过SPI寄存器级配置实现StealthChop静音驱动与SpreadCycle高动态响应模式的无缝切换,在3D打印、CNC、机器人关节等场景中显著提升能效比与控制带宽。本文围绕TMC5130与TMC5160的硬件架构差异、寄存器操作时序、驱动模式物理机制及FreeRTO

weixin_35797963的博客 410

Winsock程序设计初步之<一> Winsock编程原理

      本课程主要讲Windows中TCP/IP编程接口Winsock,版本为1.1。高版本的Winsock实际与1.1版相差不多,主要是进行了一些扩充,如可超越TCP/IP协议直接用socket来实现IPX、NETBIOS等其它通信协议。这叙述方便在本文的其余部分中提到的Winsock指的就是Winsock1.1。通过Winsock可实现点对点或广播通信程序,实际这两者之间的区别不大

cnviolet的专栏 1474

告别臃肿VS!仅用Visual Studio 2022 Build Tools为Qt 5.12.12配置MSVC2017开发环境

本文详细介绍了如何仅使用Visual Studio 2022 Build Tools为Qt 5.12.12配置MSVC2017开发环境,避免安装臃肿的完整VS。通过精准选择组件、配置Qt Creator编译器和优化Kit设置,实现高效、精简的Windows平台Qt开发环境搭建,特别适合追求性能和资源优化的开发者。

weixin_30340617的博客 350

从.bib到.bbl:手把手教你搞定LaTeX参考文献的完整流程

本文详细介绍了从.bib到.bbl的LaTeX参考文献处理完整流程,包括文献数据库构建、样式选择、主文档配置、编译流程及问题排查。特别针对.bib、.bbl等文件的操作提供了实战解决方案,帮助用户高效管理学术文献引用,适用于各类学术写作场景。

weixin_29292431的博客 285

Winsock程序设计初步之<四> Winsock函数用法说明

WSAStartup()连结应用程序与Winsock.DLL 的第一个函数。格 式: int WSAStartup( WORD wVersionRequested,LPWSADATA lpWSAData )参 数:wVersionRequested 欲使用的 Windows Sockets API 版本lpWSAData 指向 WSADATA 资料的指标传回值:成功

cnviolet的专栏 1257

告别CNN局限:用Transformer+迁移学习搞定高光谱图像分类(附Pytorch代码)

本文探讨了如何利用Transformer的自注意力机制和迁移学习策略解决高光谱图像分类中的挑战。通过结合CNN的局部特征提取和Transformer的全局建模能力,提出的DenseTransformer架构在多个数据集上实现了显著的性能提升。文章还提供了详细的PyTorch实现代码和工程优化技巧,帮助开发者快速应用这一技术。

weixin_32771907的博客 605

Winsock程序设计初步之<二> 源程序实例(一)

 //A simplest web server//Written by Shen zhiliang for learning Winsock & HTTPfile://zhiliang@sina.com #include "winsock.h"#include "stdio.h"#include "conio.h"#include "io.h"#define

cnviolet的专栏 1145

倒立摆的PLC控制(模型分析+ SCL源代码)

首先简单介绍下倒立摆模型,下面这幅图是MATLAB网站上的倒立摆模型,下面我们利用牛顿第二运动定律建立摆杆的运动方程。

RXXW_Dor的博客 3333

【制作100个Unity游戏之35】从零开始构建类《月圆之夜》《杀戮尖塔》的卡牌游戏(附带项目源码)

本文介绍了如何从零开始构建类似《月圆之夜》《杀戮尖塔》的卡牌游戏。主要内容包括:1)获取游戏素材资源;2)导入xyframe框架工具集;3)实现手牌弯曲排列效果,通过样条曲线控制卡牌位置和旋转;4)设计可扩展的MVD卡牌系统架构,分离数据层(ScriptableObject存储)、模型层(业务逻辑)和视图层(显示控制)。文中提供了完整的代码实现,并展示了卡牌动态排列的GIF效果演示。

向宇的博客,专注php/web全栈 unity游戏开发,欢迎大家评论纠错 1429

Winsock程序设计初步之<三> 源程序实例(2)

//A simplest web client //Written by Shen zhiliang for learning Winsock & HTTP//zhiliang@sina.com//1998.7.29#include "winsock.h"#include "stdio.h"#define BUFLEN 4096void SocketError(char

cnviolet的专栏 1134

【BlueDroid】【BLE】低功耗蓝牙客户端和服务端开发流程解析(超详细)

1. 精讲):SPP/A2DP/AVRCP/HFP/PBAP/IAP2/HID/MAP/OPP/PAN/GATTC/GATTS/HOGP等协议理论2. 欢迎大家关注和订阅,和专栏会持续更新中.....敬请期待!

风云说通信 1925

基于MFC的大型数据文件处理方法

      在Visual C++中,MFC(微软基础类库)提供了CFile和CStdioFile两个类来进行程序中的文件输入输出操作。Cfile类提供了基于二进制流的文件操作,功能类似于C语言中的fread()和fwrite()函数。CStdioFile提供了基于字符串流的文件操作,功能类似于C语言中的fgets()和fputs()函数。但是,使用这两个类进行文件操作时,对于一次文件读写的数据量

cnviolet的专栏 1111

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

实现类似IE的打印网页功能

       当我们点击工具条上的“打印”按钮实现IE的打印函数功能时,发现没有“打印机安 装”对话框显示出来,程序会自动开始打印文档。这个特点也被用于Microsoft Word中。 在应用程序中实现这个特点,编码如下: void CMyBrowser::OnPrint() { LPOLECOMMANDTARGET pCmdTarg = NULL; m_pDisp = m_WebBrowser

cnviolet的专栏 997

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

将图象列表转换成设备无关位图

       在我的PrintTree例子中,我想打印彩色的树控制.对于文本很容易,但是图标就不简单了.我试着将图象列表转换成DIB,但是我真正需要的是一个方法,能够取出一个ICON的DIB,而不是整个图象列表。下面就是我使用的具体方法:HANDLE CAdvancedTreeCtrl::ImageToDIB( CImageList* pImageList, int iImageNumber, C

cnviolet的专栏 798

【数据结构-5】单链表的实现

单链表,具体来说是单向的、不带头的、不循环的链表。链表由一个一个节点组成,每个节点分为数据域和指针域,数据域存放数据,指针域存放下一节点的地址。这样,就可以根据指针域中的地址找到下一个节点,节点就串起来了构成了单链表。

weixin_44218929的博客 187

工厂设备接MES为什么慢:协议识别与点表配置自动化的技术拆解

工业现场设备接 MES 的周期主要消耗在协议识别与点表配置。本文拆解这条链路的四层结构,给出点表映射的数据模型、两种部署架构的对比,以及可直接落地的三项验收口径与校验代码。适合工控集成、MES 实施、设备联网方向的工程师。

emfuture的博客 388

C# 数据结构和特殊类型

.NET Core(现称.NET)提供丰富数据结构,优化性能与开发效率。日常开发首选List<T>和Dictionary<TKey,TValue>;高性能场景推荐Span<T>与Memory<T>减少内存分配;并发环境使用ConcurrentDictionary等线程安全集合;避免非泛型集合如ArrayList。

cccloveforever的博客 674

list

的底层是双向链表结构,双向链表中每个元素存储在互不相关的独立节点中,在节点中通过指针指向其前一个元素和后一个元素。,因此反向迭代器的实现可以借助正向迭代器,即:反向迭代器内部可以包含一个正向迭代器,对正向迭代器的接口进行包装即可。是可以在常数范围内在任意位置进行插入和删除的序列式容器,并且该容器可以前后双向迭代。迭代到该位置,在这段位置上迭代需要线性的时间开销;最大的缺陷是不支持任意位置的随机访问,比如:要访问。还需要一些额外的空间,以保存每个节点的相关联信息。个元素,必须从已知的位置。

xie0510_的博客 272

向 excel、word、pdf 三种文档中占位符插入数据

【代码】向 excel、word、pdf 三种文档中占位符插入数据。

weixin_45934659的博客 56

软件商店常见问题标准处理流程

从底层软件源来看,/etc/apt/sources.list配置错误、源地址失效、公网与内网离线源混用、ARM64与x86_64架构源串用,以及DNS解析异常、系统代理配置错误,都会导致商店无法获取应用数据;打开该应用,确认可正常运行;软件商店作为系统内置的图形化软件分发与安装入口(UKUI桌面配套组件,底层依赖APT软件源),承担着应用软件的浏览、搜索、下载、安装、升级与卸载等核心功能,是终端软件部署与管理的关键通道。覆盖软件商店启动、页面加载、应用下载、安装、卸载、搜索、自身更新等全部业务场景。

qq_39496637的博客 273
上一篇: 实现类似IE的打印网页功能
下一篇: 串行通信的基本原理及用MFC实现串口通信编程
cnviolet
博客等级 码龄26年 10粉丝 15原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值