MFC桌面应用嵌入子进程界面方法及其消息同步

简述

 	之前在工作中开发了一款嵌入百度地图的插件(.dll),集成到系统软件中测试发现在操作地图后软件内存一直在增长,而且刷新不能释放。起初怀疑是MFC的webbrowser控件缓存未释放,也尝试使用ChtmlView类进行开发,任然没有解决该问题。后来在浏览器上测试百度地图,内存也在一直增长,短时间内不能释放。
 	为了不让内存增长影响到系统软件,最终决定将地图插件封装成程序(.exe),通过进程加载到系统软件。应为地图插件在百度地图上做了二次开发,所以开发的重点是系统软件与地图插件的通信,以及消息的同步。

实现过程

MFC程序嵌入子进程界面的数据通信主要用共享内存实现,消息的同步主要用父进程及子进程的窗口句柄通过sendmessage同步。具体实现步骤如下:
1.	将父进程中需要嵌入子进程界面的句柄写入共享内存中;并使用CreateProcess函数启动子进程。
2.	在子进程中读取共享内存中的父进程句柄,以该句柄为父句柄,创建子进程界面。创建子进程界面成功后,将子进程界面句柄写入共享内存。使用Sendmessage将子进程界面创建成功消息发送给父进程。
3.	父进程中收到子进程消息后,读取共享内存,保存子进程界面句柄,将子进程界面显示到父进程中指定的位置。至此,父进程与子进程之间消息可通过Sendmessage同步发送,数据可通过共享内存同步读写。
时序图如下:

![这里写图片描述](https://img-blog.csdn.net/20180131105103786?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvZmlzaF85NDgxMDk3NjU=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)

共享内存实现类:

//共享内存头文件SharedMemory.h
#pragma once
#include 
#include 
#include 
#include "Single.h"

using namespace std;

#define  MEMORYSIZE 10240 //每块内存的大小

struct MemoryAddr{
	wstring StrName;
	LPVOID pBuffer;    
	HANDLE m_Handle;
};

class SharedMemory
{
public:
	SharedMemory(void);
	~SharedMemory(void);
public:
	int m_iMemoeryNum;        //开辟内存数

	CMySingleLock		m_mapMemoryInfoLock;
	map m_mapMemoryInfo;

	LPVOID Init(wstring MeName);
	void   IntPutData(wstring MeName,LPVOID Lpvoid,int ibuflen);
	LPVOID OutPutData(wstring MeName);
};
//共享内存Cpp文件SharedMemory.cpp
#include "StdAfx.h"
#include "CMapViewOfFile.h"

SharedMemory::SharedMemory(void)
{
	m_iMemoeryNum=0;
}

SharedMemory::~SharedMemory(void)
{
	try
	{
		map::iterator it;

		m_mapMemoryInfoLock.Lock();
		for (it=m_mapMemoryInfo.begin();it!=m_mapMemoryInfo.end();it++)
		{        
			::UnmapViewOfFile(it->second.pBuffer);
			::CloseHandle(it->second.m_Handle);
		}

		m_mapMemoryInfo.clear();
		m_mapMemoryInfoLock.UnLock();
	}
	catch (...)
	{
	}
}

LPVOID SharedMemory::Init( wstring MeName)
{
	MemoryAddr mMemoryAddr;
	LPVOID pBuffer = NULL;
	// 首先试图打开一个命名的内存映射文件对象 
	HANDLE hMap = ::OpenFileMapping(FILE_MAP_ALL_ACCESS, 0, MeName.c_str());

	if (NULL == hMap)
	{    // 打开失败,创建之
		hMap = ::CreateFileMapping(INVALID_HANDLE_VALUE,NULL,PAGE_READWRITE,0,MEMORYSIZE,MeName.c_str());
		if (NULL == hMap)
		{
			OutputDebugString(L"CreateFileMapping 函数执行失败!!!");
			return NULL;
		}
		// 映射对象的一个视图,得到指向共享内存的指针,设置里面的数据
		pBuffer = ::MapViewOfFile(hMap, FILE_MAP_ALL_ACCESS, 0, 0, 0);
	}
	else
	{    // 打开成功,映射对象的一个视图,得到指向共享内存的指针,显示出里面的数据
		pBuffer = ::MapViewOfFile(hMap, FILE_MAP_ALL_ACCESS, 0, 0, 0);
	}

	mMemoryAddr.StrName=MeName.c_str();
	mMemoryAddr.pBuffer=pBuffer;
	mMemoryAddr.m_Handle=hMap;

	m_mapMemoryInfoLock.Lock();
	m_mapMemoryInfo.insert(pair(m_iMemoeryNum,mMemoryAddr));
	m_mapMemoryInfoLock.UnLock();

	m_iMemoeryNum++;

	return pBuffer;
}

void SharedMemory::IntPutData(wstring MeName, LPVOID lpVoid,int ibuflen)
{
	map::iterator itr;
	m_mapMemoryInfoLock.Lock();
	for (itr=m_mapMemoryInfo.begin();itr!=m_mapMemoryInfo.end();itr++)
	{
		if (MeName==itr->second.StrName)
		{
			memcpy(itr->second.pBuffer,lpVoid,ibuflen);
		}
	}
	m_mapMemoryInfoLock.UnLock();
}

LPVOID SharedMemory::OutPutData(wstring MeName)
{
	LPVOID pBuffer = NULL;
	map::iterator iter;

	m_mapMemoryInfoLock.Lock();
	for (iter=m_mapMemoryInfo.begin();iter!=m_mapMemoryInfo.end();iter++)
	{
		if (iter->second.StrName==MeName)
		{
			pBuffer = iter->second.pBuffer;
			break;
		}
	}
	m_mapMemoryInfoLock.UnLock();

	return pBuffer;
}

你可能感兴趣的:(windows桌面应用,MFC,子进程,界面,消息同步)