内存映射文件的方式进行进程间通信

前端之家收集整理的这篇文章主要介绍了内存映射文件的方式进行进程间通信前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

项目中有个场景,vb.net需要调用C++处理后的图片

原来的处理方案是,C++处理图片后,保存图片到磁盘上,VB.NET再从磁盘上进行读取。

现在想对这个方案进行优化。vb端先新建内存映射文件,再调用C++对图片进行处理,处理后的结果写入vb建好的内存映射文件,然后vb端再读取内存映射文件。这样处理就可以不用在磁盘上进行读写操作了,节约了IO资源。


内存映射文件包含虚拟内存中文件内容。利用文件与内存之间的映射,应用程序(包括多个进程)可以通过直接在内存中进行读写来修改文件

内存映射文件可以分为两种类型:

①持久内存映射文件

持久文件是与磁盘上的源文件关联的内存映射文件。在最后一个进程使用完此文件后,数据将保存到磁盘上的源文件中。这些内存映射文件适合用来处理非常大的源文件

②非持久内存映射文件

非持久文件是未与磁盘上的源文件关联的内存映射文件。当最后一个进程使用完此文件后,数据将丢失,并且垃圾回收功能将回收此文件。这些文件适用于为进程间通信(IPC)创建共享内存。


我仅仅是想进行进程之间的通信,所以选用了第二种,非持久化内存映射文件

首先vb端先分配内存空间

Imports System.IO
Imports System.IO.Compression
Imports System.IO.MemoryMappedFiles
Imports System.Threading
 
 
Dim mmf As MemoryMappedFile = MemoryMappedFile.CreateNew("img_1",1024 * 1024)

然后调用c++编译好的命令行可执行文件

Dim p As New System.Diagnostics.Process
p.StartInfo.FileName = "D:\dev\workspaces\outputForMMF\answerSheet.exe"
p.StartInfo.Arguments = imgName & " " & xmlName
p.StartInfo.UseShellExecute = False
p.StartInfo.CreateNoWindow = True
p.Start()
p.WaitForExit()

c++端,对图片文件进行处理后,存入内存映射文件
char *mmfName = "img_1";
//需要将char转为LPCWSTR
WCHAR wszClassName[20] = {0};		
memset(wszClassName,sizeof(wszClassName));  
MultiByteToWideChar(CP_ACP,mmfName,strlen(mmfName)+1,wszClassName,sizeof(wszClassName)/sizeof(wszClassName[0]));  

//打开共享的文件对象。 
HANDLE m_hMapFile = OpenFileMapping(FILE_MAP_ALL_ACCESS,FALSE,wszClassName); 
//获得映射视图
char* mmfm_base_address = (char*)MapViewOfFile(m_hMapFile,FILE_MAP_ALL_ACCESS,mmfSize);
DWORD error_code;
if(mmfm_base_address == NULL){
	error_code = GetLastError();
	if(error_code != SUCCESS){
		cout<<"error code "<<error_code<<endl;
	}
}else{
	//由于C++中对图片的处理使用的是openCV,图片的格式是iplImage。需要将iplImage转为bmp,再存入内存映射文件,这样vb端才能解析出来。
	//Iplimage *temp;存放的是处理好的图片结果,是全局变量
	//以下的部分,是把iplimage转为bmp

	//FILE	*fpw;
	//变量定义  
	BITMAPFILEHEADER strHead;
	BITMAPINFOHEADER strInfo; 
	//初始化头文件。用0来填充内存区域
	SecureZeroMemory(&strHead,sizeof(strHead));  
	SecureZeroMemory(&strInfo,sizeof(strInfo));
	//初始化灰度图调色板
	RGBQUAD *strPla = (RGBQUAD *)malloc(256*sizeof(RGBQUAD));//调色板的大小为1024字节
	for (int i1 = 0; i1 < 256; i1++ ){
		strPla[i1].rgbRed = strPla[i1].rgbGreen = strPla[i1].rgbBlue = i1;
		strPla[i1].rgbReserved = 0;
	}
	//写bitmapFileHeader
	strHead.bfType = 0x4d42;//写入字符"BM"
	strHead.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + 1024 + (temp->width + 3)/4*4 * temp->height;  
	strHead.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + 1024;
	//写bitmapInfoHeader
	strInfo.biSize = sizeof(strInfo);
	strInfo.biHeight = temp->height;
	strInfo.biWidth = temp->width;
	strInfo.biPlanes = 1;
	strInfo.biBitCount = 8;
	strInfo.biCompression = BI_RGB;
	/*//保存bmp图片  
	if((fpw=fopen("M://abc.bmp","wb"))==NULL){  
		cout<<"create the bmp file error!"<<endl;  
		return NULL;  
	}
	fwrite(&strHead,1,sizeof(strHead),fpw); 
	fwrite(&strInfo,sizeof(strInfo),fpw);
	fwrite(strPla,1024,fpw);
	BYTE *imagedata = NULL;
	imagedata = (BYTE*)malloc((testBitmap->width + 3)/4*4 * testBitmap->height);
	for (int k1 = 0; k1 < testBitmap->height; ++k1){
		for	(int k2 = 0; k2 < testBitmap->width; ++k2){
			if (getPixelByTemp(testBitmap,k2,k1)){
				//黑
				(*(imagedata + (testBitmap->height - k1 - 1) * ((testBitmap->width + 3)/4*4) + k2)) = 0;
			}else{
				//白
				(*(imagedata + (testBitmap->height - k1 - 1) * ((testBitmap->width + 3)/4*4) + k2)) = 255;
			}
		}
	}
	fwrite(imagedata,(testBitmap->width + 3)/4*4 * testBitmap->height,fpw);
	fclose(fpw); */

	CopyMemory(mmfm_base_address,&strHead,sizeof(strHead));

	char	*imgData = temp->imageData;
	char	*data = NULL;

	if (temp->nChannels == 3){
		data = (char*)malloc((temp->width + 3)/4*4 * temp->height);
		for(int i=0;i<temp->height;i++) for(int j=0;j<(temp->width + 3)/4*4;j++)	
			data[i * ((temp->width + 3)/4*4) + j] = temp->imageData[3*((temp->height - i - 1) * ((temp->width + 3)/4*4) + j)];	
		CopyMemory(mmfm_base_address + sizeof(strHead),&strInfo,sizeof(strInfo));
		CopyMemory(mmfm_base_address + sizeof(strHead) + sizeof(strInfo),strPla,1024);
		CopyMemory(mmfm_base_address + sizeof(strHead) + sizeof(strInfo) + 1024,data,(temp->width + 3)/4*4 * temp->height);
	}else if (temp->nChannels == 1){
		strInfo.biHeight = -strInfo.biHeight;

		CopyMemory(mmfm_base_address + sizeof(strHead),imgData,(temp->width + 3)/4*4 * temp->height);
		//for(int i=0;i<temp->height;i++) for(int j=0;j<(temp->width + 3)/4*4;j++)
		//data[i * ((temp->width + 3)/4*4) + j] = temp->imageData[((temp->height - i - 1) * ((temp->width + 3)/4*4) + j)];
	}else{
		return false;
	}

	/*fwrite(data,fpw);
	fclose(fpw);*/ 

			
			
	/*FILE	*fpw2;
	if((fpw2=fopen("M://abc2.bmp","wb"))==NULL){  
		 cout<<"create the bmp2 file error!"<<endl;  
		return NULL;  
	}
	fwrite(mmfm_base_address,((testBitmap->width + 3)/4*4 * testBitmap->height + + sizeof(strHead) + sizeof(strInfo) + 1024),fpw2);
	fclose(fpw2);*/

	//卸载映射
	UnmapViewOfFile(mmfm_base_address);
	//关闭内存映射文件
	CloseHandle(m_hMapFile);
}

完成了C++端的调用后,vb还需读出存入内存映射文件中的图片
Using mmf As MemoryMappedFile = MemoryMappedFile.OpenExisting("img_1")
	Using Stream As MemoryMappedViewStream = mmf.CreateViewStream()
		Dim reader As BinaryReader = New BinaryReader(Stream)
		Dim bytes As Byte() = reader.ReadBytes(1024 * 1024)
                'byte()转为bitmap
                Dim newBitmap As Bitmap = Bitmap.FromStream(New MemoryStream(bytes))
                newBitmap.Save("M:\" & mappingName & ".bmp")
        End Using
End Using
mmf.Dispose()
这样就完成了VB与C++两个进程之间的通信。 原文链接:https://www.f2er.com/vb/257321.html

猜你在找的VB相关文章