WINAPI C - CreateFileMapping失败,错误8 - ERROR_NOT_ENOUGH_MEMORY

时间:2017-09-02 11:54:39

标签: c file winapi memory mapping

我在Windows上处理文件映射但遇到了一些麻烦。 首先,我有必要部分映射文件并动态设置它的开始和结束。

我的代码如下:

long fiveMB = 5 * pow(2, 20);
for(int i=0;i<parts;i++){
    long start = (i)*fiveMB;
    long end = (i + 1)*fiveMB;
    long realEnd = end;
    if (roundedDim<realEnd)
        realEnd = dim;

    long chunkDim = realEnd - start;
    LARGE_INTEGER fileMapStart.QuadPart = (start/granularity)*granularity;
    LARGE_INTEGER mapViewSize.QuadPart = (start%granularity) + chunkDim;
    LARGE_INTEGER fileMapSize.QuadPart = start + chunkDim;
    long offset = start - fileMapStart.QuadPart;

    HANDLE fileMappingH= CreateFileMapping(fileH, NULL, PAGE_READONLY, fileMapSize.HighPart, fileMapSize.LowPart, NULL);

    if(fileMappingH == INVALID_HANDLE_VALUE || fileMappingH == NULL){
       printf("Error mapping file: %d\n",GetLastError());
       CloseHandle(fileH);
       return 1;
    }

    char *mapView = (char *)MapViewOfFile(fileMappingH, FILE_MAP_READ, fileMapStart.HighPart, fileMapStart.LowPart, mapViewSize.QuadPart);
    if ((LPVOID)mapView == NULL) {
        printf("Error mapView: %d\n", GetLastError());
        CloseHandle(fileMappingH);
        CloseHandle(file);
        return 1;
    }

    mapView += offset;

    /* doing all the stuff */

    UnmapViewOfFile((LPVOID)mapView);
    CloseHandle(fileMappingH);
}

据我所知,只有MapViewOfFile要求起始字节与系统粒度一致,所以我没有费心去修复最大文件映射大小。

我通过GlobalMemoryStatusEx(&amp; memstatus)和 memstatus.ullAvailVirtual 1482159字节)上尝试了此代码>我得到 2092208128字节,但仍然坚持让CreateFileMapping调用失败并且错误代码为8 ERROR_NOT_ENOUGH_MEMORY

我也尝试调用 CreateFileMapping(fileH,NULL,PAGE_READONLY,0,0,NULL)来对整个文件进行内存映射,但是 MapViewOfFile 存在问题,错误5,ERROR_ACCESS_DENIED

我不明白我在这里做错了什么,因为我在同一个项目的Linux版本上成功地使用了mmap。

感谢任何可能提供帮助的人。

编辑:

  • c是一个剩余的,我实际上是指我

  • 添加了UnmapViewOfFile和CloseHandle调用

1 个答案:

答案 0 :(得分:3)

  

据我所知,MapViewOfFile只需要起始字节   与系统粒度一致,所以我没有费心去修复   最大文件映射大小。

这是错误的根源 - 真的来自MapViewOfFile

  

dwNumberOfBytesToMap [in]

     

映射到视图的文件映射的字节数。 所有字节   必须在CreateFileMapping 指定的最大大小范围内。如果   此参数为0(零),映射从指定的扩展   偏移到文件映射的末尾。

如果我们在CreateFileMapping中使用0作为 MaximumSize ,则文件映射对象的最大大小等于文件的当前大小。并且:

  

如果应用程序指定文件映射对象的大小   大于磁盘上实际命名文件的大小,如果是   页面保护允许写访问(即 flProtect   参数指定 PAGE_READWRITE PAGE_EXECUTE_READWRITE ),   然后增加磁盘上的文件以匹配指定的大小   文件映射对象。

以及约GetLastError和win32错误。大多数情况下的错误从内核返回NTSTATUS代码。 win32层通过RtlNtStatusToDosError将指定的NTSTATUS代码转换为等效的系统错误代码。很遗憾,这种转换不是单射的 - 许多不同的NTSTATUS代码都可以转换为相同的win32错误,我们在这里丢失了敏感信息。

因此,在某些情况下,更好一些电话RtlGetLastNtStatus()而不是GetlastError() - 这会提供更多关于错误的信息。

  

CreateFileMapping调用失败并显示错误代码   ERROR_NOT_ENOUGH_MEMORY

基于错误ERROR_NOT_ENOUGH_MEMORY,我们可以认为系统中的内存不足(STATUS_NO_MEMORY)。还有另一种状态 - STATUS_SECTION_TOO_BIG转换为ERROR_NOT_ENOUGH_MEMORYCreateFileMappingZwCreateSection上的薄壳,STATUS_SECTION_TOO_BIG返回时:

  

MaximumSize 的值太大。这种情况发生时    MaximumSize 大于部分的系统定义的最大值,或者 MaximumSize 大于指定的文件和   部分不可写

这正是您的情况:您在调用PAGE_READONLY中使用CreateFileMapping - 因此部分不可写 fileMapSize 大于指定文件(文件映射对象的大小,大于磁盘上实际文件的大小)

  

MapViewOfFile返回ERROR_ACCESS_DENIED

再次GetLastError()在这里和我们一起玩一个残酷的玩笑。初始状态不是STATUS_ACCESS_DENIED我们可以等待的方式,而是STATUS_INVALID_VIEW_SIZE。此状态也转换为ERROR_ACCESS_DENIEDMapViewOfFile得到的不是CreateFileMapping

指定的最大大小内的所有字节

并在循环中多次调用CreateFileMapping - 这是设计错误 - 需要在循环之前调用此api一次。在循环中只存在感知调用MapViewOfFile。测试代码可以是:

void TestMap(PCWSTR lpFileName, ULONG dwChunkSize)
{
    HANDLE hFile = CreateFileW(lpFileName, FILE_GENERIC_READ, FILE_SHARE_VALID_FLAGS, 0, OPEN_EXISTING, 0, 0);

    if (hFile != INVALID_HANDLE_VALUE)
    {
        FILE_STANDARD_INFO fsi;
        if (GetFileInformationByHandleEx(hFile, FileStandardInfo, &fsi, sizeof(fsi)))
        {
            if (HANDLE hSection = CreateFileMappingW(hFile, 0, PAGE_READONLY, 0, 0, 0))
            {
                if (ULONG n = (ULONG)((fsi.EndOfFile.QuadPart + (dwChunkSize - 1)) / dwChunkSize))
                {
                    LARGE_INTEGER ofs = {};
                    do 
                    {
                        if (PVOID pv = MapViewOfFile(hSection, FILE_MAP_READ, ofs.HighPart, ofs.LowPart, --n ? dwChunkSize : 0))
                        {
                            UnmapViewOfFile(pv);
                        }
                        else
                        {
                            RtlGetLastNtStatus();
                        }
                    } while (ofs.QuadPart += dwChunkSize, n);
                }

                CloseHandle(hSection);
            }
            else
            {
                RtlGetLastNtStatus();
            }
        }
        CloseHandle(hFile);
    }
    else
    {
        RtlGetLastNtStatus();
    }
}