Как переназначить представление разделяемой памяти через объект сопоставления файлов?

Скажем, если у меня есть общий объект сопоставления файлов:

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 КБ, когда все, что мне может понадобиться для чтения, может быть намного меньше этого.

0

Решение

для этой задачи нужно использовать 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 КБ (крошечный размер) лучше всего будет просто отобразить все страницы за один вызов

1

Другие решения

Возможно, я неправильно понял вопрос, поэтому, пожалуйста, потерпите меня. Я решил, что проще показать то, что я говорил в комментариях, с помощью некоторого рабочего кода. @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?

Пример выше достигает этого. Если не Я неправильно понял ваш запрос, и в этом случае, если вы сможете уточнить, это было бы здорово.

1

По вопросам рекламы [email protected]