使用其他功能访问文件映射

时间:2011-07-12 16:48:29

标签: c++ memory-mapped-files

你好我有一个正确创建和映射文件的进程1(mmap for windows)。我可以正确地访问mmap en中的数据,而另一个进程我可以读取数据。

当我想使用process1的其他功能访问映射文件时出现问题。

我像这样创建映射文件:

TCHAR szName[]=TEXT("Global\\MyFileMappingObject");

int mancontrol(void* pvBrick, HANDLE hMutex);

int main()
{
    //Handels and vars for IPC
    HANDLE hMapFile;
    LPCTSTR pBuf;
    char szMsg[256];
    string dataStr = "";

     //Create file mapping
     hMapFile = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, BUF_SIZE, szName);
     if (hMapFile == NULL)
     {
        printf("Failed to create a mmap \n");

        return 1;
     }

    //Map file(MapViewOfFile) and return pointer of the mapped file(file view)
    pBuf = (LPTSTR) MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, BUF_SIZE);
    if (pBuf == NULL)
    {
       printf("Failed to map mmap");
       CloseHandle(hMapFile);

      return 1;
   }

在我想访问映射文件并向其写入数据的函数中,如下所示:

int mancontrol(void* pvBrick, HANDLE hMutex, LPCSTR pBuf)
{
    char Msg[256];
    string dataString = "";
    dataString = "AAAA en BBBB";
    strcpy(Msg, dataString.c_str());
    CopyMemory((PVOID)pBuf, Msg,  strlen(Msg));
    dataString = "";

我没有得到新的错误但是proces2无法读取数据(主要是我发送的数据,process2可以读取)。我是否需要在函数中打开映射文件并再次映射?或者我的论点传递有什么问题吗?

2 个答案:

答案 0 :(得分:1)

看起来创建内存映射的进程在其他进程有机会链接到映射之前就会退出,在这种情况下,如果Windows删除映射,我不会感到惊讶。如何在您的申请中及时订购?

答案 1 :(得分:1)

我会说bert-jan的猜测是正确的。

您可以通过将实际文件句柄从CreateFile()作为第一个参数传递给CreateFileMapping()来映射到真实磁盘文件,然后映射文件将保持不变并且其数据仍可访问。

另一方面,您已将INVALID_HANDLE_VALUE作为第一个参数传递,该参数创建临时内存文件。只要文件没有映射,它就会被删除。当第二个进程创建映射时,它会获得一个全新的文件。

在现实生活中,这两个过程可能会运行更长时间,因此这可能不是问题。

为了好玩,我敲了一个快速示例程序。如果该程序被称为fmap.exe(我的测试版本是),则将一个实例作为“fmap server”运行,将第二个实例作为“fmap”运行(这是客户端。

在客户端中键入文本,服务器将打印该文本。

// fmap.cpp 

#include <Windows.h>
#include <iostream>
#include <string>
#include <algorithm>
#include <stdexcept>

// convenience class to manage a mutex
class CMutex
{
public:
    CMutex(const char *szName)
    {
        std::string sName = std::string("MUTEX_") + szName;
        m_hMutex = ::CreateMutex(
                        NULL,           //  __in_opt  LPSECURITY_ATTRIBUTES lpMutexAttributes,
                        FALSE,          //  __in      BOOL bInitialOwner,
                        sName.c_str()); //  __in_opt  LPCTSTR lpName
        if (!m_hMutex)
            throw std::runtime_error("Failed to create mutex");
    }
    ~CMutex()
    {
        if (m_hMutex)
            ::CloseHandle(m_hMutex);
    }
    void Lock()
    {
        ::WaitForSingleObject(m_hMutex, INFINITE);
    }
    void Unlock()
    {
        ::ReleaseMutex(m_hMutex);
    }

private:
    HANDLE m_hMutex;
};

// convenience class to lock a mutex and unlock it when it
// goes out of scope.
class CAutoLock
{
public:
    CAutoLock(CMutex &m)
    : m_mutex(m)
    {
        m_mutex.Lock();
    }
    ~CAutoLock()
    {
        m_mutex.Unlock();
    }
private:
    CMutex &m_mutex;
};

// Class to manage a mapped file
// uses the same name for the file and the mutex
class CMappedFile 
{
public:
    CMappedFile(const char *szName)
    : m_hMapFile(NULL)
    , m_szBuff(NULL)
    , m_mutex(szName)
    {
        m_hMapFile = CreateFileMapping(
                            INVALID_HANDLE_VALUE,  // HANDLE hFile,
                            NULL,                  // LPSECURITY_ATTRIBUTES lpFileMappingAttributes,
                            PAGE_READWRITE,        // DWORD flProtect,
                            0,                     // DWORD dwMaximumSizeHigh,
                            nBuffSize,             // DWORD dwMaximumSizeLow,
                            szName);               // LPCTSTR lpName 
        if (!m_hMapFile)
            throw std::runtime_error("Failed to create mapping");

        m_szBase = 
            reinterpret_cast<char *>(
                    MapViewOfFile(
                            m_hMapFile,           //  HANDLE hFileMappingObject,
                            FILE_MAP_ALL_ACCESS,  //  DWORD dwDesiredAccess,
                            0,                    //  DWORD dwFileOffsetHigh,
                            0,                    //  DWORD dwFileOffsetLow,
                            nBuffSize));          //  DWORD dwNumberOfBytesToMap
        if (!m_szBase)
            throw std::runtime_error("Failed to create view");

        // reserve first few bytes of the file for a length variable.  
        // The rest is the buffer.
        m_szBuff = m_szBase + sizeof(size_t);
    }

    ~CMappedFile()
    {
        if (m_szBase)
        {
            UnmapViewOfFile(m_szBase);
        }
        if (m_hMapFile)
        {
            CloseHandle(m_hMapFile);
        }
    }

    // add a string to the mapped file
    void Put(const std::string &sVal)
    {
        // lock mutex
        CAutoLock l(m_mutex);

        // create reference to beginning of the buffer
        size_t &nLength = *reinterpret_cast<size_t *>(m_szBase);

        // check for overflow
        if (nLength + sVal.length() >= nBuffSize)
            throw std::runtime_error("Buffer Overflow");

        // copy string to buffer and increment length
        std::copy(sVal.begin(), sVal.end(), m_szBuff + nLength);
        nLength += sVal.length();
    }

    // read a string from the mapped file and
    // clear the length field, indicating that
    // this data has been read.
    std::string Get()
    {   
        // lock mutex
        CAutoLock l(m_mutex);

        // create reference to beginning of the buffer
        size_t &nLength = *reinterpret_cast<size_t *>(m_szBase);

        std::string sVal;
        if (nLength)
        {
            // if anything is in the buffer read ot
            sVal.assign(m_szBuff, nLength);

            // reset length as we've read the buffer
            nLength = 0;
        }
        return sVal;
    }

private:
    HANDLE m_hMapFile;
    char * m_szBase;
    char * m_szBuff;
    CMutex m_mutex;

    enum { 
        nBaseSize=1024,                     // whole file size
        nBuffSize=nBaseSize-sizeof(size_t)  // buffer size, after size has been reserved
    };
};

void DoClient(CMappedFile &m);
void DoServer(CMappedFile &m);

int main(int argc, char* argv[])
{
    try
    {
        const char szUniqueName[] = "CA249329_ACAE_11E0_9594_6CF0494804C2";
        CMappedFile m(szUniqueName);

        std::string sServer("server");
        if (argc==2 && sServer==argv[1])
            DoServer(m);
        else
            DoClient(m);
    }
    catch (std::exception &e)
    {
        std::cerr << e.what() << std::endl;
    }

    return 0;
}

void DoClient(CMappedFile &m)
{
    std::cout << "Client running\n\n";
    std::string s;
    while (std::getline(std::cin, s))
        m.Put(s);
}

void DoServer(CMappedFile &m)
{
    std::cout << "Server running\n\n";
    while (1)
    {
        std::string s = m.Get();
        if (s.length())
            std::cout << s << std::endl;
    }
}