简述
之前在工作中开发了一款嵌入百度地图的插件(.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 <string>
#include <wtypes.h>
#include <map>
#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<int,MemoryAddr> 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<int,MemoryAddr>::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<int,MemoryAddr>(m_iMemoeryNum,mMemoryAddr));
m_mapMemoryInfoLock.UnLock();
m_iMemoeryNum++;
return pBuffer;
}
void SharedMemory::IntPutData(wstring MeName, LPVOID lpVoid,int ibuflen)
{
map<int,MemoryAddr>::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<int,MemoryAddr>::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;
}