SetEndOfFile error 1224: ERROR_USER_MAPPED_FILE, 即使文件映射成功关闭

SetEndOfFile error 1224: ERROR_USER_MAPPED_FILE, even the file mapping closed successfully

我正在编写一个使用文件映射注销到文件的程序。
当我想读取日志时,调用 Logger::Destroy() 以便将写入文件映射视图的内容刷新到物理文件。 代码如下:

int Logger::Destroy() {
    if (m_lpMapAddress) {
        auto bRet = UnmapViewOfFile(m_lpMapAddress);
        // succeed
    }

    if (m_hMapFile) {
        auto bRet = CloseHandle(m_hMapFile);
        // succeed
        m_hMapFile = NULL;
    }

    int nSize = m_lpCurAddress - m_lpMapAddress;
    if (nSize > 0
        && nSize < (1024 * 1024 * 16 * 2))
    {
        DWORD dwPtr = SetFilePointer(m_hFile, nSize, 0, FILE_BEGIN);

        ///// Succeed
        // if (dwPtr == INVALID_SET_FILE_POINTER)
        //  DbgViewOut(__FUNCTION__ " SetFilePointer error: %d \n", GetLastError());

        //// Error occurs :  "SetEndOfFile returned : 0 1224"
        BOOL bRet = SetEndOfFile(m_hFile);
        DbgViewOut(__FUNCTION__ " SetEndOfFile returned : %d %d\n", bRet, GetLastError()); 
    
        ....
    }

    m_lpMapAddress = m_lpCurAddress = NULL;

    return 0;
}

问题SetEndOfFile()ERROR_USER_MAPPED_FILE 失败,甚至 CloseHandle(m_hMapFile) 成功。 所以我用谷歌搜索了微软关于文件映射的手册,并对其中的一些进行了评论。

https://docs.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-closehandle

Closing a handle to a file mapping can succeed even when there are file views that are still open. For more information, see Closing a File Mapping Object.

https://docs.microsoft.com/en-us/windows/win32/memory/closing-a-file-mapping-object

When each process finishes using the file mapping object and has unmapped all views, it must close the file mapping object's handle and the file on disk by calling CloseHandle. These calls to CloseHandle succeed even when there are file views that are still open. However, leaving file views mapped causes memory leaks.

它说我不敢相信CloseHandle()的结果。
而且我找不到解决方案。

有人可以帮助我吗?谢谢。


Addition: I called Logger::Destroy() in std::lock_guard<std::mutex>, can this affect to the trouble?

: I've tested this, lock doesn't affect to it.


UPDATE: I've read . And I think there isn't a very big difference. I append the code of Logger::Initialize() which initializes the filemapping.
And also, Logger::Initialize() and Logger::Destroy() both are in same process&thread, no need to be shared with others.

int Logger::Initialize()
{
  m_hFile = CreateFileA(
      m_zFileName.c_str()
      , GENERIC_READ | GENERIC_WRITE
      , FILE_SHARE_READ | FILE_SHARE_WRITE
      , NULL                          
      , CREATE_ALWAYS
      , FILE_ATTRIBUTE_NORMAL
      , NULL);

  if (m_hFile == INVALID_HANDLE_VALUE) {
      DbgViewOut(__FUNCTION__  " CreateFileA error: %d \n", GetLastError());
      return -1;
  }

  m_hMapFile = CreateFileMappingA(
      m_hFile
      , NULL
      , PAGE_READWRITE
      , 0
      , 1024 * 1024 * 16 * 2
      , m_zMapKey.c_str());

  if (!m_hMapFile) {
      DbgViewOut(__FUNCTION__  " CreateFileMapping error: %d \n", GetLastError());
      return -1;
  }

  m_hMapFile = OpenFileMappingA(FILE_MAP_WRITE, TRUE, m_zMapKey.c_str());
  if (m_hMapFile == NULL) {
      DbgViewOut(__FUNCTION__ " OpenFileMapping error: %d \n", GetLastError());
      return -1;
  }

  m_lpMapAddress = (BYTE*)MapViewOfFile(
      m_hMapFile              // handle to mapping object
      , FILE_MAP_ALL_ACCESS   // read/write
      , 0                 // high-order 32 bits of file offset
      , 0                 // low-order 32 bits of file offset
      , 0);                // number of bytes
  if (m_lpMapAddress == NULL) {
      DbgViewOut(__FUNCTION__ " MapViewOfFile error: %d \n", GetLastError());
      return -1;
  }

  m_lpCurAddress = m_lpMapAddress;

  return 0;
}

我会回答我自己的问题。

问题是我在 CreateFileMappingA() 之后调用了 OpenFileMappingA(),所以 CreateFileMappingA() 返回的 m_hMapFile 泄漏了。 我删除了 OpenFileMappingA(),问题消失了。

我以前知道它必须在创建句柄后打开一次,几个月前我曾经在进程之间的内存共享中这样做过。 但是在争论中,我意识到创建后打开句柄是不必要的。

非常感谢@RemyLebeau 的详细建议。

int Logger::Initialize()
{
    m_hFile = CreateFileA(
        m_zFileName.c_str()
        , GENERIC_READ | GENERIC_WRITE
        , FILE_SHARE_READ | FILE_SHARE_WRITE
        , NULL                          
        , CREATE_ALWAYS
        , FILE_ATTRIBUTE_NORMAL
        , NULL);

    if (m_hFile == INVALID_HANDLE_VALUE) {
        DbgViewOut(__FUNCTION__  " CreateFileA error: %d \n", GetLastError());
        return -1;
    }


    m_hMapFile = CreateFileMappingA(
        m_hFile
        , NULL
        , PAGE_READWRITE
        , 0
        , LINM_LOGGER_FILE_MAXSIZE * 2
        , m_zMapKey.c_str());

    if (!m_hMapFile) {
        DbgViewOut(__FUNCTION__  " CreateFileMapping error: %d \n", GetLastError());
        return -1;
    }

//// This was the solution - CreateFileMappingA & OpenFileMappingA mustn't be used for same process or thread.
//
//  m_hMapFile = OpenFileMappingA(FILE_MAP_WRITE, TRUE, m_zMapKey.c_str());
//  if (m_hMapFile == NULL) {
//      DbgViewOut(__FUNCTION__ " OpenFileMapping error: %d \n", GetLastError());
//      return -1;
//  }

    m_lpMapAddress = (BYTE*)MapViewOfFile(
        m_hMapFile              // handle to mapping object
        , FILE_MAP_ALL_ACCESS   // read/write
        , 0                 // high-order 32 bits of file offset
        , 0                 // low-order 32 bits of file offset
        , 0);                // number of bytes
    if (m_lpMapAddress == NULL) {
        DbgViewOut(__FUNCTION__ " MapViewOfFile error: %d \n", GetLastError());
        return -1;
    }

    m_lpCurAddress = m_lpMapAddress;

    return 0;
}