65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIconstarIconstarIconstarIcon

5.00/5 (8投票s)

2008年9月1日

CPOL
viewsIcon

86120

downloadIcon

2255

这又是一个关于内存映射文件的例子。 与其他示例不同的是,这里有一个 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);
            }
        }
    }
}

关注点

此代码在投入生产使用之前需要进行一些更新。

  1. 从 MMF 中删除键(以及由此产生的内存整理)。
  2. 变长的的数据。
  3. MMF 的自动调整大小。

我打算随着时间的推移发布改进。

© . All rights reserved.