如何在 C++ DLL 中使用 CreateFileMapping 并从 C#、VB 和 C++ 中访问它





5.00/5 (8投票s)
这又是一个关于内存映射文件的例子。 与其他示例不同的是,这里有一个 SetData(TCHAR* Key, TCHAR* value) / GetData(TCHAR* key) 模式,这很酷。
引言
这是一个如何像一个映射一样,使用共享内存的 SetData/GetData 模式的示例。
void SetData(TCHAR* key, TCHAR* value)
TCHAR* GetData(TCHAR* key)
通过对代码进行轻微改进,可以使用此模式存储和检索变长二进制数据(例如图像)。
背景
有关 CreateFileMapping
的基本教程,请参阅此处。
使用代码
代码和示例解释了如何从 VB.NET、C# 和 C++ 使用此共享内存。
在附带的代码中,一个 C++ DLL(名为 SharedMem.DLL)模拟了一个 map<T,T>
(Dictionary
/Hashtable
),以便可以在进程间使用。 数据共享基于 MMF。
C# 示例如下所示
[DllImport("sharedmem.dll")]
extern static int GetRecordCount();
[DllImport("sharedmem.dll")]
extern static void SetValue(
[MarshalAs(UnmanagedType.LPTStr)] string key,
[MarshalAs(UnmanagedType.LPTStr)] string value);
[DllImport("sharedmem.dll")]
extern static IntPtr GetValue([MarshalAs(UnmanagedType.LPTStr)]string key);
private void OnSetClick(object sender, EventArgs e)
{
//Set Func
SetValue(keyText, valueText);
}
private void OnGetClick(object sender, EventArgs e)
{
//Get
IntPtr intPtr = GetValue(keyText);
textBox.Text = Marshal.PtrToStringUni(intPtr);
}
代码非常容易理解。
MMF 在 DLLMain.cpp 中创建/打开。
// sharedmem.cpp : Defines the exported functions for the DLL application.
//
#include "stdafx.h"
#include "sharedmem.h"
#include "tchar.h"
#include "stdio.h"
extern HANDLE m_hFileMMF, m_pViewMMFFile, hMutex;
class CMutex
{
public:
CMutex()
{
if(!hMutex){
hMutex = CreateMutex(
NULL, // default security attributes
FALSE, // initially not owned
L"Global\\MMFMutex"); // unnamed mutex
}
WaitForSingleObject( hMutex, INFINITE);
}
~CMutex()
{
ReleaseMutex(hMutex);
}
};
void SetRecordCount(int value)
{
TCHAR* record = (TCHAR*)m_pViewMMFFile;
swprintf_s(record, MAX_PATH, L"RECCNT=%d#", value);
}
extern "C" int GetRecordCount()
{
TCHAR* record = (TCHAR*)m_pViewMMFFile;
TCHAR temp[MAX_PATH];
int recordCount = -1;
TCHAR seps[] = L"=#";
TCHAR *token1 = NULL;
TCHAR *next_token1 = NULL;
_tcscpy_s(temp, MAX_PATH, record);
token1 = _tcstok_s ( temp, seps, &next_token1);
if(token1 && _tcscmp(token1, _T("RECCNT")) == 0)
{
token1 = _tcstok_s ( NULL, seps, &next_token1);
recordCount = _ttoi(token1);
}else
{
recordCount = 1;
SetRecordCount(1);
}
return recordCount;
}
int nRecordCount = -1;
void RemoveValue(TCHAR* key)
{
TCHAR* record = (TCHAR*)m_pViewMMFFile;
TCHAR temp[MAX_PATH];
nRecordCount = GetRecordCount();
record+=MAX_PATH;
//Try to look. If found, break out of for loop
//Compact the memory immediately immediately
//If you get time, strongly advice you to do a lazy compaction
bool isRecordFound = false;
int i;
for(i= 1; i< nRecordCount; i++,record+=MAX_PATH)
{
TCHAR seps[] = L"=#";
TCHAR *token1 = NULL;
TCHAR *next_token1 = NULL;
_tcscpy_s(temp, MAX_PATH, record);
token1 = _tcstok_s ( temp, seps, &next_token1);
if(_tcscmp(token1, key) == 0)
{
isRecordFound = true;
break;
}
}
//start moving the records
for(; i< nRecordCount-1; i++, record+=MAX_PATH)
{
TCHAR* nextRecord = record + MAX_PATH;
_tcscpy_s(record, MAX_PATH, nextRecord);
}
}
TCHAR* IfExists(TCHAR* key, TCHAR** value = NULL)
{
TCHAR* record = (TCHAR*)m_pViewMMFFile;
TCHAR temp[MAX_PATH];
nRecordCount = GetRecordCount();
record+=MAX_PATH;
for(int i=1; i< nRecordCount; i++,record+=MAX_PATH)
{
TCHAR seps[] = L"=#";
TCHAR *token1 = NULL;
TCHAR *next_token1 = NULL;
_tcscpy_s(temp, MAX_PATH, record);
token1 = _tcstok_s ( temp, seps, &next_token1);
if(_tcscmp(token1, key) == 0)
{
token1 = _tcstok_s ( NULL, seps, &next_token1);
//return a copy of the value
if(value!=NULL)
{
int len = _tcslen(token1)+1;
*value = new TCHAR(len);
_tcscpy_s(*value, len, token1);
}
return record;
}
}
return NULL;
}
extern "C" TCHAR* GetValue(TCHAR* key)
{
TCHAR* sRetVal = new TCHAR[MAX_PATH];
CMutex mutex;
TCHAR* data = NULL;
if(m_pViewMMFFile)
{
IfExists(key, &data);
}
return data;
}
extern "C" void SetValue(TCHAR* key, TCHAR* value)
{
CMutex mutex;
if(m_pViewMMFFile )
{
if(value == NULL)
{
RemoveValue(key);
}
else
{
TCHAR* data = IfExists(key);
if(data == NULL)
{
data = new TCHAR[MAX_PATH];
swprintf_s(data, MAX_PATH, L"%s=%s#", key, value);
//Add to end of the MMF
TCHAR* record = (TCHAR*)m_pViewMMFFile;
record += MAX_PATH*nRecordCount;
nRecordCount++;
SetRecordCount(nRecordCount);
_tcscpy_s(record, MAX_PATH, data);
delete data;
}
else
{
//Replace existing
swprintf_s(data, MAX_PATH, L"%s=%s#", key, value);
}
}
}
}
关注点
此代码在投入生产使用之前需要进行一些更新。
- 从 MMF 中删除键(以及由此产生的内存整理)。
- 变长的的数据。
- MMF 的自动调整大小。
我打算随着时间的推移发布改进。