【问题标题】:Win32 Can't get data from shared memoryWin32 无法从共享内存中获取数据
【发布时间】:2017-11-09 21:22:14
【问题描述】:

我能够创建一个共享内存对象,并使用 MSDN 中的指南打开它。

第一个进程创建它并使其保持打开状态。 第二个进程输入一个字符串。 然后第一个过程将尝试恢复该字符串并显示它,但是我似乎什么也得不到。尽管看起来写作部分设置正确,但它始终是空的。

我这样写一个字符串到内存中:

int MemoryMapper::Write(const std::string& data) {

    m_pBuffer = (LPCTSTR)MapViewOfFile(m_OpenHandle, FILE_MAP_ALL_ACCESS, 0, 0, m_BufferSize);

    if (m_pBuffer == NULL)
    {
        std::cerr << m_DebugErrorTitle << "Write(): " << MM_ERROR_MAPPING_FAILED << " {" << GetLastError() << "}" << std::endl;
        Close();
        return 0;
    }

    const char* cdata = _CharFromString(data);
    int size = (lstrlen(cdata) * sizeof(const char*));

    CopyMemory((PVOID)m_pBuffer, cdata, size);
    m_WrittenSize += size;

    if (m_Debug > 1) { std::cout << m_DebugTitle << "Wrote " << size << " bytes." << std::endl; }
    return size;
}

然后我是这样读的:

int MemoryMapper::Read(std::string& data) {

    m_pBuffer = (LPCTSTR) MapViewOfFile(m_OpenHandle, FILE_MAP_ALL_ACCESS, 0, 0, m_BufferSize);

    if (m_pBuffer == NULL)
    {
        std::cerr << m_DebugErrorTitle << "Read(" << m_MemoryName << "): " << MM_ERROR_MAPPING_FAILED << " {" << GetLastError() << "}" << std::endl;
        Close();
        return 0;
    }

    MessageBox(NULL, m_pBuffer, TEXT("TEST MESSAGE"), MB_OK);

    int size = (lstrlen(m_pBuffer) * sizeof(const char*));
    UnmapViewOfFile(m_pBuffer);
    return size;
}

m_pBuffer 是一个 LPCTSTR,m_BufferSize 是 1024。 为对象指定的名称在两端相同。我已经确保创建和打开/关闭部分正常工作。

第二个进程写入'8312.000000,8312.000000',按照代码一共92个字节。

阅读器的缓冲区是空的。

我做错了什么? 我尝试了各种数据类型,char、const char、string、tchar - 结果相同。

【问题讨论】:

    标签: c++ shared-memory


    【解决方案1】:

    8312.000000,8312.000000 的长度为 23 个字符。

    std::string::c_str() 返回一个以 null 结尾的 char* 指针。 lstrlen() 返回最多但不包括空终止符的字符数。

    Write() 将字符串长度乘以sizeof(const char*),在 32 位进程中为 4(在 64 位进程中为 8)。 Write() 超出了data 的范围并试图将23 * 4 = 92 字节复制到m_pBuffercdata 保证指向包含 24 最大字节数(23 个字符 + 1 个空终止符)的缓冲区,因此 Write() 正在进入周围的内存。那是未定义的行为任何事情都可能发生。在您的情况下,您可能只是将额外的垃圾复制到m_pBufferWrite() 可能很容易崩溃。

    事实上,如果 data 的字符数超过 256 个,Write() 会崩溃,因为它会尝试将 257+ * 4 &gt; 1024 字节复制到 m_pBuffer - 超过 MapViewOfFile() 的映射访问权限。

    您应该将字符串长度乘以 sizeof(std::string::value_type),而不是 sizeof(char),它始终为 1(因此您可以省略乘法)。

    Read() 有同样的sizeof() 错误,但它也假设m_pBuffer 在调用lstrlen()MessageBox() 时总是以空值结尾,但Write() 不保证空值终止符始终存在。

    话虽如此,请尝试更多类似的东西:

    int MemoryMapper::Write(const std::string& data)
    {
        // include the null terminator if there is room...
        DWORD size = std::min(data.size() + 1, m_BufferSize);
    
        char *pBuffer = (char*) MapViewOfFile(m_OpenHandle, FILE_MAP_WRITE, 0, 0, size);
        if (!pBuffer)
        {
            DWORD errCode = GetLastError();
            std::cerr << m_DebugErrorTitle << "Write(): " << MM_ERROR_MAPPING_FAILED << " {" << errCode << "}" << std::endl;
            Close();
            return 0;
        }
    
        CopyMemory(pBuffer, data.c_str(), size);
        UnmapViewOfFile(pBuffer);
    
        m_WrittenSize += size;
    
        if (m_Debug > 1) {
            std::cout << m_DebugTitle << "Wrote " << size << " bytes." << std::endl;
        }
    
        return size;
    }
    
    int MemoryMapper::Read(std::string& data)
    {
        char *pBuffer = (char*) MapViewOfFile(m_OpenHandle, FILE_MAP_READ, 0, 0, m_BufferSize);
        if (!pBuffer)
        {
            DWORD errCode = GetLastError();
            std::cerr << m_DebugErrorTitle << "Read(" << m_MemoryName << "): " << MM_ERROR_MAPPING_FAILED << " {" << errCode << "}" << std::endl;
            Close();
            return 0;
        }
    
        // check for a null terminator, but don't exceed the buffer...
        char *terminator = std::find(pBuffer, pBuffer + m_BufferSize, '\0');
        std::size_t len = std::distance(pBuffer, terminator);
    
        data.assign(pBuffer, len);
        UnmapViewOfFile(pBuffer);
    
        MessageBoxA(NULL, data.c_str(), "TEST MESSAGE", MB_OK);
    
        // include the null terminator if it was read...
        return std::min(len + 1, m_BufferSize);
    }
    

    【讨论】:

    • 感谢您的精彩解释。我已根据您的建议实施了更改,并且写入发生在 24 个字节,但是我仍然无法读取它。没有收到任何消息。
    • 实际上,不同共享记忆的命名还有一个错误,现在在您的指导下可以正常工作。非常感谢。
    猜你喜欢
    • 1970-01-01
    • 2013-05-05
    • 1970-01-01
    • 2023-01-12
    • 1970-01-01
    • 2019-08-03
    • 1970-01-01
    • 1970-01-01
    • 2018-03-11
    相关资源
    最近更新 更多