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

3 篇文章 1 订阅

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

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

现在想对这个方案进行优化。内存映射文件的形式进行进程间通信是Windows下最高效的方法,因此打算用内存映射文件的形式来连接两个进程。.net端先新建内存映射文件,再调用C++对图片进行处理,处理后的结果写入.net端建好的内存映射文件中,然后.net端再读取内存映射文件。这样处理就可以不用在磁盘上进行读写操作了,节约了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,0,sizeof(wszClassName));  
MultiByteToWideChar(CP_ACP,0,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, 0, 0, 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,1,sizeof(strInfo),fpw);
	fwrite(strPla,1,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,1,(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), &strInfo,sizeof(strInfo));
		CopyMemory(mmfm_base_address + sizeof(strHead) + sizeof(strInfo), strPla, 1024);
		CopyMemory(mmfm_base_address + sizeof(strHead) + sizeof(strInfo) + 1024, 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,1,(testBitmap->width + 3)/4*4 * testBitmap->height,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,1,((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++两个进程之间的通信。 


  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值