Скажем, если у меня есть общий объект сопоставления файлов:
HANDLE hFileMapping = ::CreateFileMapping(INVALID_HANDLE_VALUE, &sa,
PAGE_READWRITE, 0, 0x8000, L"MyObjectName");
и я получил небольшой кусок для просмотра, как таковой:
BYTE* pData = (BYTE*)::MapViewOfFile(hFileMapping, FILE_MAP_READ, 0, 0, 0x10);
if(!pData) return false; //fail
DWORD dwcbFullSize = *(DWORD*)(pData + 0xC);
Итак, если мне нужно будет выделить больше данных, будет ли приемлемым MapViewOfFile
снова как таковой без первого отображения pData
?
BYTE* pFullData = (BYTE*)::MapViewOfFile(hFileMapping,
FILE_MAP_READ, 0, 0, dwcbFullSize);
PS. Моя цель не состоит в том, чтобы тратить циклы ЦП на отображение всего сегмента разделяемой памяти 32 КБ, когда все, что мне может понадобиться для чтения, может быть намного меньше этого.
для этой задачи нужно использовать SEC_RESERVE
атрибут при создании файла сопоставления (раздел)
Если объект сопоставления файлов поддерживается подкачкой операционной системы
файл ( hfile параметр INVALID_HANDLE_VALUE), указывает, что
когда представление файла отображается в адресное пространство процесса,
Весь диапазон страниц зарезервирован для последующего использования процессом
чем совершено. Зарезервированные страницы могут быть зафиксированы в последующих вызовах
VirtualAlloc
функция. После того, как страницы зафиксированы, они не могут
быть освобожден или списан сVirtualFree
функция. Этот атрибут
не влияет на объекты сопоставления файлов, которые поддерживаются исполняемым файлом
файлы изображений или файлы данных ( hfile параметр является дескриптором файла).
SEC_RESERVE нельзя сочетать с SEC_COMMIT.
поэтому после создания раздела с SEC_RESERVE
Атрибут нужно один раз вызвать MapViewOfFile
— этот вызов не резервирует диапазон памяти, но не фиксирует страницы. для фиксации страницы нужно звонить VirtualAlloc
, наконец, мы можем освободить всю память по вызову UnmapViewOfFile
void DoDemo(ULONG cb)
{
if (!cb)
{
return;
}
SYSTEM_INFO si;
GetSystemInfo(&si);
cb = (cb + (si.dwPageSize - 1)) & ~(si.dwPageSize - 1);
if (HANDLE hFileMapping = CreateFileMapping(INVALID_HANDLE_VALUE, 0,
PAGE_READWRITE|SEC_RESERVE, 0, cb, L"MyObjectName"))
{
// reserve address space with PAGE_READWRITE initial protection
PVOID BaseAddress = MapViewOfFile(hFileMapping,
FILE_MAP_READ|FILE_MAP_WRITE, 0, 0, cb);
// hFileMapping no more need
CloseHandle(hFileMapping);
if (BaseAddress)
{
// check, for test only
::MEMORY_BASIC_INFORMATION mbi;
if (VirtualQuery(BaseAddress, &mbi, sizeof(mbi)) < sizeof(mbi) ||
mbi.Type != MEM_MAPPED || mbi.State != MEM_RESERVE)
{
__debugbreak();
}
// map page by page
PBYTE pb = (BYTE*)BaseAddress;
do
{
if (!VirtualAlloc(pb, si.dwPageSize, MEM_COMMIT, PAGE_READWRITE))
{
GetLastError();
break;
}
*pb = '*';//write something
} while (pb += si.dwPageSize, cb -= si.dwPageSize);
//unmap all
UnmapViewOfFile(BaseAddress);
}
}
}
однако все это имеет смысл делать только для больших по размеру разделов. для 32 КБ (крошечный размер) лучше всего будет просто отобразить все страницы за один вызов
Возможно, я неправильно понял вопрос, поэтому, пожалуйста, потерпите меня. Я решил, что проще показать то, что я говорил в комментариях, с помощью некоторого рабочего кода. @OP, может быть, отсюда вы можете уточнить, если это не отвечает на ваши вопросы?
Поэтому я взял пример кода, предложенного MSFT, и взломал его вместе, чтобы продемонстрировать то, что я говорил (так что код по сути является примером кода MS).
https://msdn.microsoft.com/en-us/library/windows/desktop/aa366551(v=vs.85).aspx
Вы можете создать VS Solution с 2 проектами, вот код для проекта / процесса A:
#include <windows.h>
#include <stdio.h>
#include <conio.h>
#include <tchar.h>
#define BUF_SIZE 256
TCHAR szName[] = TEXT("Global\\MyFileMappingObject");
TCHAR szMsg[] = TEXT("Message from first process.");
int _tmain()
{
HANDLE hMapFile;
LPCTSTR pBuf;
hMapFile = CreateFileMapping(
INVALID_HANDLE_VALUE, // use paging file
NULL, // default security
PAGE_READWRITE, // read/write access
0, // maximum object size (high-order DWORD)
BUF_SIZE, // maximum object size (low-order DWORD)
szName); // name of mapping object
if (hMapFile == NULL)
{
_tprintf(TEXT("Could not create file mapping object (%d).\n"),
GetLastError());
return 1;
}
pBuf = (LPTSTR)MapViewOfFile(hMapFile, // handle to map object
FILE_MAP_ALL_ACCESS, // read/write permission
0,
0,
BUF_SIZE);
if (pBuf == NULL)
{
_tprintf(TEXT("Could not map view of file (%d).\n"),
GetLastError());
CloseHandle(hMapFile);
return 1;
}CopyMemory((PVOID)pBuf, szMsg, (_tcslen(szMsg) * sizeof(TCHAR)));
_getch();
UnmapViewOfFile(pBuf);
CloseHandle(hMapFile);
return 0;
}
Теперь вот некоторый модифицированный код для второго проекта / процесса B.
Смотрите это для справки: https://msdn.microsoft.com/en-us/library/windows/desktop/aa366548(v=vs.85).aspx
#include <windows.h>
#include <stdio.h>
#include <conio.h>
#include <tchar.h>
#pragma comment(lib, "user32.lib")
#define BUF_SIZE 256
TCHAR szName[] = TEXT("Global\\MyFileMappingObject");
int mapDataAtOffset(DWORD offset, size_t bytesToRead, LPVOID* outData, LPVOID* outMapAddress);
int _tmain()
{
LPCTSTR pBuf;
LPVOID outMapAddress = nullptr;
LPVOID outMapAddress2 = nullptr;
auto ret = mapDataAtOffset(0, 8, (LPVOID*)&pBuf, &outMapAddress);
MessageBox(NULL, pBuf, TEXT("Process2"), MB_OK);
ret = mapDataAtOffset(8, 8, (LPVOID*)&pBuf, &outMapAddress2);
MessageBox(NULL, pBuf, TEXT("Process2"), MB_OK);
if(outMapAddress)UnmapViewOfFile(outMapAddress);
if (outMapAddress2)UnmapViewOfFile(outMapAddress2);
return 0;
}
int mapDataAtOffset(DWORD offset, size_t bytesToRead, LPVOID* outData, LPVOID* outMapAddress) {
HANDLE hMapFile; // handle for the file's memory-mapped region
BOOL bFlag; // a result holder
DWORD dBytesWritten; // number of bytes written
DWORD dwFileMapSize; // size of the file mapping
DWORD dwMapViewSize; // the size of the view
DWORD dwFileMapStart; // where to start the file map view
DWORD dwSysGran; // system allocation granularity
SYSTEM_INFO SysInfo; // system information; used to get granularity
LPVOID lpMapAddress; // pointer to the base address of the
// memory-mapped region
char * pData; // pointer to the data
int i; // loop counter
int iData; // on success contains the first int of data
int iViewDelta; // the offset into the view where the data
//shows up
DWORD FILE_MAP_START = offset;
// Get the system allocation granularity.
GetSystemInfo(&SysInfo);
dwSysGran = SysInfo.dwAllocationGranularity;
// Now calculate a few variables. Calculate the file offsets as
// 64-bit values, and then get the low-order 32 bits for the
// function calls.
// To calculate where to start the file mapping, round down the
// offset of the data into the file to the nearest multiple of the
// system allocation granularity.
dwFileMapStart = (FILE_MAP_START / dwSysGran) * dwSysGran;
_tprintf(TEXT("The file map view starts at %ld bytes into the file.\n"),
dwFileMapStart);
// Calculate the size of the file mapping view.
dwMapViewSize = (FILE_MAP_START % dwSysGran) + bytesToRead;
_tprintf(TEXT("The file map view is %ld bytes large.\n"),
dwMapViewSize);
// How large will the file mapping object be?
dwFileMapSize = FILE_MAP_START + bytesToRead;
_tprintf(TEXT("The file mapping object is %ld bytes large.\n"),
dwFileMapSize);
// The data of interest isn't at the beginning of the
// view, so determine how far into the view to set the pointer.
iViewDelta = FILE_MAP_START - dwFileMapStart;
_tprintf(TEXT("The data is %d bytes into the view.\n"),
iViewDelta);
hMapFile = OpenFileMapping(
FILE_MAP_ALL_ACCESS, // read/write access
FALSE, // do not inherit the name
szName); // name of mapping object
if (hMapFile == NULL)
{
_tprintf(TEXT("Could not open file mapping object (%d).\n"),
GetLastError());
return 1;
}
// Map the view and test the results.
lpMapAddress = MapViewOfFile(hMapFile, // handle to
// mapping object
FILE_MAP_ALL_ACCESS, // read/write
0, // high-order 32
// bits of file
// offset
dwFileMapStart, // low-order 32
// bits of file
// offset
dwMapViewSize); // number of bytes
// to map
if (lpMapAddress == NULL)
{
_tprintf(TEXT("lpMapAddress is NULL: last error: %d\n"), GetLastError());
return 3;
}
// Calculate the pointer to the data.
pData = (char *)lpMapAddress + iViewDelta;
*outData = pData;
*outMapAddress = lpMapAddress;
CloseHandle(hMapFile); // close the file mapping object, doesn't matter as long as view is still mapped
return 0;
}
Итак, чтобы ответить на ваш вопрос
будет ли приемлемо снова вызывать MapViewOfFile как таковой без предварительного отображения pData?
Пример выше достигает этого. Если не Я неправильно понял ваш запрос, и в этом случае, если вы сможете уточнить, это было бы здорово.