




已阅读5页,还剩27页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
分类号:TP311.1 U D C:D10621-408-(2007)6179-0密 级:公 开 编 号:2003032155成都信息工程学院学位论文内存映射文件在进程中的应用与研究论文作者姓名:金佳华申请学位专业:网络工程申请学位类别:工学学士指导教师姓名(职称):王永丽(副教授)论文提交日期:2007年7月25日内存映射文件在进程中的应用与研究摘 要随着计算机操作系统的发展,多任务多进程已经被广泛应用。为了加速应用程序的运行,往往会在系统中建立多个进程,由这些进程相互合作去完成一个共同的任务,经常需要在进程之间交换信息、传递数据。Windows提供了多种机制,使应用程序能够迅速而方便地共享数据和信息,这些机制包括RPC、COM、OLE、DDE、窗口消息(尤其是WM_COPYDATA)、剪贴板、邮箱、管道和套接字等;而这些机制均使用内存映射文件,在Windows系统中,单个计算机上共享数据的最低层机制是内存映射文件。如果互相进行通信的所有进程都在同一台计算机上的话,使用内存映射文件进行共享,系统的性能较高和开销较小。本文主要阐述了内存映射文件基本原理和实现方法,探讨和研究了如何在Visual C+环境下利用MFC类库编写使用内存映射文件来完成进程间数据共享,并给出了应用实例。关键词:内存映射文件;进程通信;MFCApplication and Research of Memory-mapped Files in Process AbstractWith the development of computer operating system, multi-task process has been used more widely. In order to accelerate the application of the operation, it often creates a number of processes in the system. These processes cooperate to accomplish a common task, often exchanging information and data transfer in the processWindows offers a variety of mechanisms for enabling the applications to share data and information quickly and easily. These mechanisms include the RPC, COM, OLE and DDE, information window (especially WM_COPYDATA), the clipboard, mailboxes, pipes and sockets. These mechanisms are used memory mapping file in the Windows system. The memory-mapped file is used in these mechanisms of windows. The memory-mapped file is the lowest level on the single computer for sharing data mechanism. If the processes that are communicating with each other are all in the same machine, the system will acquire higher function with smaller expense by using the memory-mapping file to share data.This paper discusses the basic principles and the methods of the memory-mapped files mainly. We will explore and study how to use memory-mapped files for complete inter-process data sharing by using MFC in Visual C +. An example is given. Key words: Memory-mapped files; Process communication; MFC目 录论文总页数:28页1引 言11.1课题背景11.2本课题研究的意义11.3课题研究方法12 开发平台简介13 主要技术23.1内存映射文件的基本原理和操作23.1.1内存映射文件的基本原理23.1.2创建内存映射文件33.1.3映射文件的视图到进程的地址空间53.1.4FlushViewOfFile函数63.1.5取消文件视图的映射63.1.6关闭文件映射对象63.2内存映射文件在进程数据共享中的应用63.2.1进程的相关概念63.2.2共享内存的原理73.2.3使用事件对象来同步进程84 应用实例 104.1相关技术104.1.1消息映射机制104.1.2BMP(位图)文件114.2本实例实现流程144.3功能实现154.3.1MemonyShare工程说明154.3.2MemonyShareRev工程说明20结束语26参考文献26致 谢27声 明281 引 言1.1 课题背景随着计算机操作系统的发展,多任务多进程已经被广泛应用。同时也就涉及到进程之间的通信和数据共享等问题。在Windows中,在单个计算机上共享数据的最低层机制是内存映射文件。如果互相进行通信的所有进程都在同一台计算机上的话,如RPC、COM、OLE、DDE、窗口消息(尤其是WM_COPYDATA)、剪贴板、邮箱、管道和套接字等所有机制均使用内存映射文件从事它们的烦琐工作。所以研究内存映射文件的原理,在实际编程中实现进程的共享成了本课题的主要研究对象。1.2 本课题研究的意义内存映射文件是实现进程共享通讯的基础,它也是Windows的一种内存管理方法,提供了一个统一的内存管理特征,使应用程序可以通过内存指针对磁盘上的文件进行访问,其过程就如同对加载了文件的内存的访问,非常方便和高效。内存映射文件是多个进程间共享数据最有效的方法,通过研究内存映射原理,熟悉方法并将其应用到实际的工程中,加以实践,掌握进程间通讯的方法。本文主要阐述如何在Visual C+环境下,运用MFC实现使用内存映射文件进行进程间数据共享的方法。1.3 课题研究方法进程间的通讯类型有多种,本课题主要是研究利用内存映射文件来实现基于共享存储区的通信方式,这样的通信方式一般适合于传输大量数据。Visual C+是一个很好的可视化编程工具。作为Windows环境下最主要的应用开发系统之一,Visual C+不仅是C+语言的集成开发环境,而且与Win32紧密相连,所以利用Visual C+开发系统可以完成各种各样的应用程序的开发,从底层软件直到上层直接面向用户的软件。使用Visual C+环境来开发基于Windows的应用程序大大缩短了开发时间。使用Visual C+2005,运用MFC设计一个使用内存映射文件来传递BMP文件到另一进程显示的实例,并分析相关代码。2 开发平台简介Visual C+自诞生以来,一直是Windows环境下最主要的应用开发系统之一。Visual C+不仅是C+语言的集成开发环境,而且与Win32紧密相连,所以利用Visual C+开发系统可以完成各种各样的应用程序的开发,从底层软件直到上层直接面向用户的软件。而MFC编程是在Visual C+的一种编程方法。MFC是用来编写Windows应用程序的C+类集,该类集以层次结构组织起来,其中封装了大部分Windows API函数和Windows控件,他所包含的功能涉及到整个Windows操作系统。MFC不仅为用户提供了Windows图形环境下应用程序的框架,而且还提供了创建应用程序的组件。使用MFC类库和Visual C+提供的高度可视的应用程序开发工具,可使应用程序开发变得更简单,开发周期极大地缩短,提高代码的可靠性和可重用性。代码重用是C+长期寻求的目标。对于C+程序员而言,重用通常是指从先前已有的积累派生新的C+类的技术。MFC正好提供了大量的基类供程序员根据不同的应用环境进行扩充。MFC提供的类库对程序设计的高度抽象,使得程序员的主要精力不用放在程序设计的细节实现上,而是放在程序的功能拓展上面,它同时允许在变成过程中自定义和扩展应用程序中的类,MFC同时还允许对Windows API进行存取,从而使应用程序以最小的规模实现最丰富的功能,而且提供高效率的运行代码。MFC是C+语言中的一个安全子集,它大大简化了使用C+开发基于Windows应用程序的工作。MFC精心设计的类库结构,以一种直观的软件包的形式把进行Windows应用开发这一过程所需的各种程序模块有机地组织起来,经验丰富的C+开发人员可以使用MFC实现C+中的高级功能。MFC被设计成可移植于众多的平台,允许其应用程序适用于多种不同平台。对于多种编译器,MFC也是可以移植的,而且又许多软件开发公司已经把它作为一种基于Windows开发标准的应用程序构架。MFC编程的一个特点是系统提供了一个“向导”(Wizard),利用“向导”,可形成应用程序的基本框架。程序员只需在形成的框架的基础上进一步添加必要的实现代码,即可编写自己的Windows应用程序。3 主要技术3.1 内存映射文件的基本原理和操作3.1.1 内存映射文件的基本原理内存文件映射是Windows的一种内存管理方法,提供了一个统一的内存管理特征,使应用程序可以通过内存指针对磁盘上的文件进行访问,其过程就如同对加载了文件的内存的访问。通过文件映射这种使磁盘文件的全部或部分内容与进程虚拟地址空间的某个区域建立映射关联的能力,可以直接对被映射的文件进行访问,而不必执行文件I/O操作也无需对文件内容进行缓冲处理。与虚拟内存相似,内存映射文件保留了一个地址空间区域,在需要时间将它提交到物理存储器。它们之间的不同点是内存映射文件提交到物理存储器的数据来自磁盘上相应的文件,而不是系统页文件。一旦文件被映射,就可以认为整个文件被加载到了内存中,可以像访问内存一样访问文件的内容。使用内存映射文件的目的有3个:l 利用内存映射文件实现调入和执行EXE文件及DLL文件,这样节省了页交换文件的空间,从而能够减少文件调入的时间。l 利用指向一块内存区域的指针即可访问映射文件的数据,有利于简化对文件的访问,也不再需要编写各种缓冲方案。l 使用内存映射文件在多个进程间共享数据。Windows也提供了其他进程间通讯的方法但是这些方法都是使用内存映射文件实现的。所以内存映射文件是进程共享最有效的方法。内存映射文件的函数包括CreateFileMapping、OpenFileMapping、MapViewOfFile、UnmapViewOfFile和FlushViewOfFile。3.1.2 创建内存映射文件使用内存映射文件可以分为两步,第一步是使用CreateFileMapping创建一个内存映射文件内核对象,告诉操作系统内存映射文件需要的物理内存大小。这个步骤决定了内存映射文件的用途究竟是为了磁盘上的文件建立内存映射还是为了多个进程共享数据建立共享内存。函数用法如下:HANDLE CreateFileMapping(HANDLE hFile,/文件的句柄LPSECURITY_ATTRIBUTES lpAttributes,/定义内存映射文件对象是否可以继承DWORD flProtect,/该内存映射文件的保护类型DWORD dwMaximumSizeHigh,/内存映射文件的长度DWORD dwMaximumSizeLow,LPCTSTR lpName/内存映射文件的名字);函数参数说明l hFile:是通过调用CreateFile或OpenFile函数返回的文件句柄,该文件的访问模式需要与参数flProtect所指定的保护模式一致。如果hFile为INVALID_HANDLE_VALUE,此时需要由参数dwMaximumSizeHigh和dwMaximumSizeLow来指明内存映射文件的空间大小。如果参数hFile取值为INVALID_HANDLE_VALUE(即0xFFFFFFFF)时,则既可以共享内存同时又不需要一个永久的磁盘文件。l lpAttributes:指向文件映射对象的安全属性结构,这个参数通常为NULL.l flProtect:用来指定文件视图的保护模式,表1列出了该参数的取值和含义。表1 flProtect参数的取值及含义值说明PAGE_READONLY文件只读,hFile代表的文件必须以GENERIC_READ方式打开PAGE_READWRITE文件可读写,hFile代表的文件必须以GENERIC_READ和GENERIC_WRITE方式打开PAGE_WRITECOPY文件可读写,在进行写操作时,会复制修改过的页面另外,可以通过安位“或”操作符将扇区的属性设置给flProctect参数,这些属性的取值及含义如表2所示。表2 参数的取值及含义值说明SEC_COMMIT在内存或页交换文件中为同一扇区的所有叶面分配无力内存地址(默认值)SEC_IMAGE文件映射信息和属性取自文件映像(Windows NT/2000/XP特有)SEC_NOCACHE未被映射的页面被置入缓存,因此系统允许直接把数据写入磁盘上的文件SEC_RESERVE保留扇区中的页面,不再用于分配物理存储。只有当参数hFile的值为INVALID_HANDLE_VALUE时才有效l dwMaximumSizeHigh:用于指定文件映射对象的最大尺寸的高32位。如果要访问的文件大于4GB才设置该值,否则该参数永远是零。l dwMaximumSizeLow:用于指定文件映射对象的最大尺寸的低32位。如果此参数设置为0,则表示文件映射对象的最大尺寸与被映射文件的尺寸相同。l lpName:指定文件映射对象的名字。如果文件映射对象创建成功,则返回文件映射对象的句柄。如果该句柄代表一个已经存在的文件映射对象,那么GetLastError()将返回一个ERROR_ALREADY_EXISTS。调用失败,函数返回为NULL。创建文件映射对象成功后,可以将文件的数据映射到进程的地址空间中。如果创建的是共享内存,其他进程不能再使用CreateFileMapping函数去创建同名的内存映射文件,而要使用OpenFileMapping函数去打开已创建好的对象,函数用法如下:HANDLE OpenFileMapping( DWORD dwDesiredAccess,/指定保护类型 BOOL bInheritHandle,/返回的句柄是否可被继承 LPCTSTR lpName/创建对象时使用的名字);l dwDesiredAccess:指定对象的保护类型有FILE_MAP_WRITE和FILE_MAP_READ,分别为可写属性和可读属性。如果CreateFileMapping和OpenFileMapping函数执行成功,返回的是内存映射文件句柄;如果函数执行失败则返回NULL.3.1.3 映射文件的视图到进程的地址空间有两个函数用来将文件的视图映射到进程的地址空间,分别是MapViewOfFile函数和MapViewOfFileEx函数。LPVOID MapViewOfFile(HANDLE hFileMappingObject,/文件映射对象的句柄 DWORD dwDesiredAccess,/指定保护类型,FILE_MAP_WRITE或FILE_MAP_READ DWORD dwFileOffsetHigh, DWORD dwFileOffsetLow, SIZE_T dwNumberOfBytesToMap);参数说明如下:l dwFileOffsetHigh:用于指定文件映射起始位置的偏移量的高32位。l dwFileOffsetLow:用于指定文件映射起始位置的偏移量的低32位。l dwNumberOfBytesToMap:指定需要映射的字节数。为0则表示文件的全部。MapViewOfFileEx是MapViewOfFile的扩展版本,允许为映射视图指定一个起始的内存地址。这个函数的参数与函数MapViewOfFile函数的参数含义一样,所不同的是扩展函数版本最后增加了一个参数lpBaseAddress,该参数用来指定视图的起始内存地址。3.1.4 FlushViewOfFile函数通过MapViewOfFile函数返回的指针修改文件内容时,修改的结果常常不会立刻反映到文件中,因为实际上是在对调入物理内存页中的数据进行修改。考虑到性能因素,该页并不会每做一次修改就立刻将该修改同步到硬盘文件中。如果需要在某个时候强制将之前所做的修改一次性同步到与之对应的硬盘文件中时,可以通过FlushViewOfFile函数达到这个目的:BOOL FlushViewOfFile(PVOID pvAddress, SIZE_T dwNumberOfBytesToFlush);这个函数传入需要将修改同步到硬盘文件中的内存块的起始地址和大小。3.1.5 取消文件视图的映射访问完视图后我们需要使用UnmapViewOfFile来取消映射。BOOL UnmapViewOfFile(LPCVOID lpBaseAddress);参数lpBaseAddress为文件视图的起始地址,该参数的值应该与MapViewOfFile函数的返回值一致3.1.6 关闭文件映射对象调用CloseHandle()函数即可关闭文件映射对象。如果忘记关闭对象,在程序继续运行时将会出现资源泄漏。虽然在程序退出运行时,操作系统会自动关闭在进程中已经打开但未关闭的任何对象。但是在进程的运行过程中,势必会积累过多的资源句柄。因此在不再需要使用对象的时候通过CloseHandle()将其予以关闭是有意义的。3.2 内存映射文件在进程数据共享中的应用3.2.1 进程的相关概念在多道程序环境下,程序的执行属于并发执行,此时它们将失去其封闭性,并具有间断性及不可再现性的特征。这决定了通常程序是不能参与并发执行的,因为程序执行的结果是不可再现的。这样程序的运行也就失去了意义。为使程序能并发执行,且为了对并发执行的程序加以描述和控制,人们引入了”进程”概念。由程序段、相关的数据段和PCB三部分组成构成了进程实体。PCB是为了程序(含数据)能独立运行而为之配置的进程控制块。进程是进程实体的运行过程,使系统资源分配和调度的一个独立单位。如图1所示。内存进程一代码页数据页进程二代码页数据页图1 进程结构示意图由于有时需要多个进程一起完成某项工作,这就需要进程之间能够互相通信和共享数据。进程通讯是指进程之间的信息交换,少者是一个状态或数值,多者则是成千上万的字节。随着OS的发展,用于进程之间实现通讯的机制也在发展,并已由早期的低级进程通讯机制(如信号量机制),发展为能传送大量数据的高级通讯工具机制。高级通信工具机制可以归结为三大类:共享存储器系统、消息传递系统以及管道通信系统。在Windows中,系统提供的进程之间的通信机制在底层实现上都是利用内存映射文件技术。如果互相进行通信的所有进程都在同一台计算机上的话,如RPC、COM、OLE、DDE、窗口消息(尤其是WM_COPYDATA)、剪贴板、邮箱、管道和套接字等所有机制均使用内存映射文件从事它们的烦琐工作。内存映射文件为不同进程共享内存提供了一个有效且简单的方法,使进程间能够很好的共享数据。本课题主要研究如何使用内存映射文件实现基于共享存储区进行进程通信的方法。3.2.2 共享内存的原理为解决进程间通信的问题,内存映射文件技术被利用作为解决方案。原来内存映射文件只映射类似磁盘一类的存储器上的文件。而为了更快速地在进程之间通信,内存映射文件还可以提交物理内存。通过让两个或多个进程映射同一个文件映射对象的视图来实现数据共享,这意味着它们将共享物理存储器的同一个页面。因此,当一个进程将数据写入一个共享文件映射对象的视图时,其他进程可以立即看到它们视图中的数据变更情况。注意,如果多个进程共享单个文件映射对象,那么所有进程必须使用相同的名字来表示该文件映射对象。进程1地址空间进程2地址空间内存.共享内存主要是通过映射机制来实现的。Windows下进程的地址空间在逻辑上是相互隔离的,但在物理上却是重叠。所谓的重叠是指同一块内存区与可能被多个进程同时使用。当调用CreateFileMapping创建命名的内存映射文件对象时,Windows即在物理内存申请一块指定大小的内存区域,返回文件映射对象的句柄hMap.为了能够访问这块内存区域必须调用MapViewOfFile函数,促使Windows将此内存空间映射到进程的地址空间中。当在其他进程访问这个块内存区域时,则必须使用OpenFileMapping函数取得对象句柄hMap,并调用MapViewOfFile函数得到此内存空间的一个映射。这样一来,系统就把同一块内存区域映射到了不同进程的地址空间中,从而达到共享内存的目的。如图2所示。图2 进程共享示意图3.2.3 使用事件对象来同步进程在OS中引入进程后,虽然提高了资源的利用率和系统的吞吐量,但由于进程的异步性也会给系统造成混乱,尤其是在他们争用临界资源时。进程同步的主要任务,是使并发执行的诸进程之间能有效地共享资源和相互合作,从而使程序的执行具有可再现性。Windows中可以创建很多种类的对象,如文件、窗口和内存等对象都是看得见摸得着的实体,事件(Event)也是一种对象,但事件对象比较抽象,可以把它看成是一个设置在Windows内部的标志,它的状态设置和测试工作由Windows来完成,Windows可以将这些标志的设置和测试工作和线程调度等工作在内部结合起来,这样效率就要高得多。事件可以有两种状态:“置位的”和“复位的”。如果想使用事件对象,需要首先使用CreateEvent函数去创建它,就像在程序中为自己的标志变量分配内存一样:HANDLE CreateEvent(LPSECURITY_ATTRIBUTES lpEventAttributes,BOOL bManualReset,BOOL bInitialState,LPTSTR lpName );函数的参数定义如下:l lpEventAttributes参数指向一个SECURITY_ATTRIBUTES结构,用来定义事件对象的安全属性,如果事件对象的句柄不需要被继承,可以在这里指定NULL。l bManualReset参数指定事件对象是否需要手动复位,如果指定TRUE,复位工作必须使用ResetEvent函数手动完成。指定FALSE的话,当测试事件的函数返回时(返回原因可能是超时,也可能是对象状态被置位引起),对象的状态会自动被复位。l bInitialState参数指定事件对象创建时的初始状态,TRUE表示初始状态是置位状态,FALSE表示初始状态是复位状态。l lpName指向一个以0结尾的字符串,用来指定事件对象的名称,和内存共享文件一样,为事件对象命名是为了在其他地方使用OpenEvent函数获取事件对象的句柄。如果不需要命名,那么可以在这里使用NULL。如果函数执行成功,函数的返回值是事件的句柄,如果失败,则返回0。当一个事件被建立后,程序就可以通过SetEvent和ResetEvent函数来设置事件的状态,就像我们使用or或and指令将程序中的标志变量置位或复位一样。BOOL SetEvent(HANDLE hEvent);/将事件的状态设为“置位”BOOL ResetEvent(HANDLE hEvent);/将事件的状态设为“复位”参数hEvent就是CreateEvent函数返回的事件句柄。当不再需要事件对象的时候,可以使用CloseHandle函数将它释放掉。就像用测试指令来测试标志一样,如果将事件看成是“标志”的话,就需要有函数来实现测试功能,WaitForSingleObject就是这样的函数,如果函数仅可以用来测试事件的状态的话,事件对象就失去了使用的初衷,因为这样的话,在线程中循环测试标志的情况又会重演了。WaitForSingleObject的用法DWORD WaitForSingleObject(HANDLE hHandle,DWORD dwMilliseconds);WaitForSingleObject函数可以测试的不仅是事件对象,它也可以用来测试线程和进程等对象的状态,hHandle参数用来指定为等待的对象句柄,dwMilliseconds参数指定以ms为单位的超时时间,当以下两种情况中的任意一种发生的时候,函数就返回。当函数的执行时间超过dwMilliseconds就返回,但如果参数dwMilliseconds为INFINITE时函数将直到相应时间事件变成有信号状态才返回,否则就一直等待下去,直到WaitForSingleObject有返回值,才执行后面的代码。4 应用实例本实例主要演示了如何使用内存映射文件来实现不同进程间的数据共享以及如何利用事件对象(Event)实现进程间同步,它将读取一个BMP文件然后传递到另外一个进程并显示出来。下面简单介绍下实例中用到的一些相关技术。4.1 相关技术4.1.1 消息映射机制MFC提供的一套消息映射机制来处理消息。所谓消息映射,简单讲,就是让程序员指定要某个MFC类(有消息处理能力的类)处理这个消息.MFC提供了工具ClassWizard来帮助实现消息映射,在处理消息的类中添加一些有关消息映射的内容和处理的成员函数.程序员将完成消息处理函数,实现所希望的消息处理能力。如果派生类要覆盖基类的消息处理函数,就用ClassWizard在派生类中添加一个消息映射条目,用同样的原型定义一个函数,然后实现该函数。这个函数覆盖派生类的任何基类的同名处理函数。使用MFC框架编程时,消息发送和处理的本质和Windows一样。但是,有一点需要强调的是,所有的MFC窗口都使用同一窗口过程,程序员不必去设计和实现自己的窗口过程,而是通过MFC提供的一套消息映射机制来处理消息。因此,MFC简化了程序员编程时处理消息的复杂性。根据处理函数和处理过程的不同, MFC主要处理三类消息:Windows 消息,前缀以“WM_”打头,WM_COMMAND例外。Windows消息直接送给MFC窗口过程处理,窗口过程调用对应的消息处理函数。一般,由窗口对象来处理这类消息,也就是说,这类消息处理函数一般是MFC窗口类的成员函数。控制通知消息,是控制子窗口送给父窗口的 WM_COMMAND通知消息。窗口过程调用对应的消息处理函数。一般,由窗口对象来处理这类消息,也就是说,这类消息处理函数一般是MFC窗口类的成员函数。需要指出的是,Win32使用新的WM_NOFITY来处理复杂的通知消息。WM_COMMAND类型的通知消息仅仅能传递一个控制窗口句柄(lparam)、控制窗ID和通知代码(wparam)。WM_NOTIFY能传递任意复杂的信息。命令消息,这是来自菜单、工具条按钮、加速键等用户接口对象的WM_COMMAND通知消息,属于应用程序自己定义的消息。通过消息映射机制,MFC框架把命令按一定的路径分发给多种类型的对象(具备消息处理能力)处理,如文档、窗口、应用程序、文档模板等对象。能处理消息映射的类必须从CCmdTarget类派生。MFC 使用ClassWizard帮助实现消息映射,它在源码中添加一些消息映射的内容,并声明和实现消息处理函数。来分析这些被添加的内容。在类的定义(头文件)里,它增加了消息处理函数声明,并添加一行声明消息映射的宏 DECLARE_MESSAGE_MAP。在类的实现(实现文件)里,实现消息处理函数,并使用 IMPLEMENT_MESSAGE_MAP宏实现消息映射。一般情况下,这些声明和实现是由MFC的ClassWizard自动来维护的。4.1.2 BMP(位图)文件BMP文件又称位图文件,它是存储在电脑上的未经压缩的图片。因为它没有被压缩,所以BMP文件显示出来的图像是最清晰的,其他格式的图片文件基本都是在BMP文件基础上压缩得到的。在图像识别和图像处理等领域,BMP文件是最重要的。从磁盘上读取BMP文件显示给用户的过程主要如下。1) 建立与应用程序窗口相兼容的内存DC,建立一个与磁盘BMP文件大小相同的、与窗口客户区DC兼容的内存Bitmap(位图)。2) 将这个内存Bitmap选入到内存DC中,这样应用程序就可以在内存DC上进行位图操作了。3) 通过分析BMP文件的格式(文件头结构和信息头结构)。将这个BMP文件画到内存DC中。4) 最后在窗口处理WM_PAINT消息时将内存DC复制到客户区DC中。下面分别讲述各部分的实现过程。1. 创建内存DC和内存Bitmap(位图)CreateComaptibleDC函数用于创建一个与指定设备环境兼容的内存设备环境。HDC CreateCompatibleDC(HDC hdc);/hdc函数为一个存在的设备环境句柄CreateCompatibleDC函数创建了一个于指定的DC兼容的内存DC。参数中的hdc只是个参考DC,该函数创建这个DC的内存映像。内存DC仅仅存在在内存中。当内存DC刚被创建时,它仅有黑白两色。在应用程序使用内存DC进行绘图操作时,它创建了一个与制定设备环境兼容的位图。这个位图能够被选入到任何内存的内存DC中。函数用法如下HBITMAP CreateCompatibleBitmap(HDC hdc,int nWidth,/位图的宽度int nHeight/位图的高度);Hdc为参考DC的设备环境句柄,必须与CreateCompatibleDC函数使用的参考句柄相兼容。CreateCompatibleBitmap函数创建的位图的颜色格式与参考DC的格式相同。它的返回值是位图句柄,可以使用SelectObject函数选入此句柄到上面创建的内存DC中。2. 在DC间复制图像在内存DC上绘制完图像之后,为了向用户显示,可以调用BitBlt把内存DC上的位图复制到真正的DC中。这就是在屏幕上快速显示图像的双缓冲技术(可以减少图像抖动)。BitBlt是一个重要的块传送操作函数。块传送指把原为之重的数据块按照指定的方式传送到目的位置中。把内存中的位图复制到窗口客户区以及在不同的DC间复制图形数据都要用到块传送操作。BitBlt函数用法如下。BOOL BitBlt(HDC hdcDest,/目标DCint nXDest,int nYDest,/指定目标DC中接受图像的起始位置int nWidth,int nHeight,/欲传送图像的宽度和高度HDC hdcSrc,/源DCint nXSrc,int nYSrc,/指定源DC中要拷贝的图像的起始坐标DWORD dwRop/传输过程要者性的光栅运算);BitBlt是”数据块传送”的意思,即“Bit Block Transfer”。这个函数可以将一个DC中的图像拷贝到另一个DC中,而不改变图像的大小。3. BMP文件结构为了将BMP文件读到内存DC中,必须要了解文件的内部结构,下面简单介绍。BMP文件的开始是BITMAPFILEHEADER结构(文件头),它的定义如下。Typedef struct tagBITMAPFILEHEADERWORD bfType;/文件标示,必需为BMDWORD bfSize;/文件长度WORD bfReserved1;/0WORD bfReserved2;/0DWORD bfOffBits;/位图数据在文件中的起始位置BITMAPFILEHEADER,*PBITMAPFILEHEADER;BITMAPFILEHEADER结构的后面是BITMAPINFOHEADER结构(信息头)。typedef struct tagBITMAPINFOHEADERDWORD biSize;/本结构的长度LONG biWidth;/位图的宽度LONG biHeight;/位图的高度WORD biPlanes;/位图的色平面数WORD biBitCount;/位图的颜色深度(一个像素所占用的位数)DWORD biCompression;/位图的压缩方式DWORD biSizeImage;/位图的尺寸LONG biXpelsPerMeter;/图形x方向的分辨率LONG biYPelsPerMeter;/图形y方向的分辨率DWORD biClrUsed;/指定了颜色表的大小DWORD biClrImportant;BITMAPINFOHEADER *PBITMAPINFOHEADER;之后是颜色表(如果有的话)。位图信息BITMAPINFO是由BITMAPINFOHEADER结构和颜色表组成的。Typedef struct tagBITMAPINFOBITMAPINFOHEADER bmiHeader;/位图信息头RGBQUAD bmiColors1;/颜色表BITMAPINFO;4.2 本实例实现流程由于实例的功能非常简单,主要就分成二个部分,分别为发送部分和接受部分。下面分别介绍发送部分和接受部分的实现流程。开始打开一个BMP检查接受进程是否存在?创建内存映射文件,发数据,发送消息m_hEvent复位等待接受进程响应内存映射文件关闭映射文件视图,关闭文件句柄存在启动接受进程不存在发送部分主要的功能是检测接受进程是否存在,如果不存在则运行接受进程然后发送位图文件。如果存在,就直接发送文件给接受进程。具体流程如图3所示。图3 发送进程流程图打开内存映射文件,映射到视图,读取数据。关闭映射视图,关闭映射文件句柄,等待消息(WM_MYPROCMSG)启动m_hEvent置位m_hEvent置位返回等待下一次传送接收部分的主要功能是等待发送部分的消息,接到发送消息后,打开内存映射文件 从中读取发送的数据,完成后返回,继续等待发送消息。它的主要流程如图4所示。图4 接收进程流程图发送进程接受进程打开文件,创建内存映射文件,等待m_hEvent置位信号发送WM_MYPROCMSGm_hEvent复位打开内存映射文件读取数据m_hEvent置位关闭内存映射文件句柄,关闭文件句柄两个进程之间的通信同步如图5所示。图5 同步示意图4.3 功能实现首先,创建两个基于对话框的MFC应用程序工程,分别将其命名为MemonyShare和MemonyShareRev.下面分别对这两个工程进行详细说明。4.3.1 MemonyShare工程说明界面部分简介为对话框放置一个文本框控件(IDC_EDIT_ProcName,变量名为m_bmpPathName)和一个PICTURE控件(IDC_PCIBMP,变量名为m_Pcibmp)。另外放置三个按钮控件,分别是“开始共享”(IDC_Btn_StartProc),“打开文件”(IDC_OPENFILE)和“共享结束”(IDC_Btn_EndData)。如图6所示。图6 发送进程(MemonyShare)界面代码部分说明首先为工程添加一个类CWriteData,该类主要提供一些函数的封装,其具体代码如下:/CWriteData头文件部分class CWriteDatapublic:/用来建立内存映射文件,并创建事件对象int run(CString m_bmpPathName);/启动一个进程void StartProc();/控制另一个进程退出void ExitProc(CString strProcName);private:/定义用于同步的事件对象的句柄HANDLE m_hEvent;/CWriteData类的实现文件#include StdAfx.h#include WriteData.h/自定义消息变量UINT WM_MYPROCMSG;UINT WM_MYDATAEND;void CWriteData:StartProc()STARTUPINFOsi;PROCESS_INFORMATIONpi;ZeroMemory(&si,sizeof(si);ZeroMemory(&pi,sizeof(pi);si.cb=sizeof(si);si.dwFlags=STARTF_USESHOWWINDOW;si.wShowWindow=1;/创建事件对象,该对象手工复位,初始为无信号状态m_hEvent=CreateEvent(NULL,TRUE,FALSE,_T(Proc_SynEvent);/建立一个新的进程if(CreateProcess(NULL,MemoryShareRev.exe,NULL,NULL,FALSE,NORMAL_PRIORITY_CLASS|CREATE_NEW_CONSOLE,NULL,NULL,&si,&pi)/等待新进程初始化结束WaitForSingleObject(m_hEvent,INFINITE);elseMessageBox(NULL,创建进程失败!,NULL,MB_OK);PostQuitMessage(0);/关闭刚刚建立的进程句柄CloseHandle(pi.hProcess);int CWriteData:run(CString picname)/创建或打开一个文件HANDLE hFile=CreateFile(picname,GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);/创建文件映射对象,这里主要用来共享一段内存HANDLE hFileMap=CreateFileMapping(hFile,NULL,PAGE_READWRITE,0,0,Syn_Mapping);/将事件设置为无信号ResetEvent(m_hEvent);/发送自定义消息给窗口,这里用的广播消息,关键字是HWND_BROADCAST。PostMessage(HWND_BROADCAST,WM_MYPROCMSG,NULL,NULL);/等待另一个进程对内存映射文件的响应WaitForSingleObject(m_hEvent,INFINITE);CloseHandle(hFileMap);CloseHandle(hFile);return 0;void CWriteData:ExitProc(CString strProcName)/控制另一个进程的退出CWnd *pOtherWnd=CWnd:FindWindow(NULL,strProcName);if(pOtherWnd)pOtherWnd-PostMessage(WM_CLOSE,NULL,NULL);elsereturn;if(NULL !=m_hEvent)CloseHandle(m_hEvent);在工程的APP文件中,即CMemonyShareApp的派生类文件中,添加如下代码:/定义消息变量extern UINT WM_MYPROCMSG;extern UINT WM_MYDATAEND;BOOL CMemonyShareApp:InitInstance()/注册用户定义的消息WM_MYPROCMSG=RegisterWindowMessage(_T(MyProgMsg);WM_MYDATAEND=RegisterWindowMessage(_T(MyDataEnd);在工程的对话框文件中需要添加如下代码:/在对话框的头文件中/包含用户定义的类文件#include WriteData.hclass CMemonyShareDlg : publi
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025年福建省南平闽延电力建设有限公司建阳分公司招聘2人考前自测高频考点模拟试题及答案详解(夺冠系列)
- 2025广西河池市凤山县农业农村局招募水稻等产业特聘农民技术员2人考前自测高频考点模拟试题及答案详解(网校专用)
- 2025湖北宜昌市点军区招聘社区专职人员(网格员)6人考前自测高频考点模拟试题附答案详解(突破训练)
- 2025北京协和医院麻醉科合同制科研助理招聘考前自测高频考点模拟试题及参考答案详解1套
- 2025年甘肃省卫生健康委系统招聘工作人员网上缴费考前自测高频考点模拟试题及参考答案详解
- 2025年河北石家庄市藁城区卫生健康局公开招聘工作人员1名考前自测高频考点模拟试题附答案详解(模拟题)
- 2025年公主岭市法院系统招聘真题
- 2025年西安明珠电力安装工程有限公司招聘(2人)模拟试卷附答案详解(完整版)
- 2025内蒙古自治区农牧业科学院纳入总量管理控制数招聘模拟试卷及答案详解(新)
- 2025福建厦门市集美区幸福幼儿园招聘1人考前自测高频考点模拟试题及1套完整答案详解
- 【课件】数学建模活动:决定苹果的最佳出售时间点课件-2025-2026学年高一上学期数学人教B版(2019)必修第一册
- 施工队进场安全教育培训
- 母婴分离护理常规
- 污泥池清理管理制度
- 秩序员休假管理制度
- 保护环境的课件
- 2025年中国张裕产区葡萄酒特色与品牌国际化发展报告
- 图深度强化学习在配电网故障恢复中的应用研究
- (2017)海南省房屋建筑与装饰装修工程综合定额交底资料
- 2024-2025学年下学期高一英语人教版同步经典题精练之语法填空
- 《社会科学研究方法》课件
评论
0/150
提交评论