Reputation: 22265
Say, if I have a shared file mapping object:
HANDLE hFileMapping = ::CreateFileMapping(INVALID_HANDLE_VALUE, &sa,
PAGE_READWRITE, 0, 0x8000, L"MyObjectName");
and I got a small chunk of it for view, as such:
BYTE* pData = (BYTE*)::MapViewOfFile(hFileMapping, FILE_MAP_READ, 0, 0, 0x10);
if(!pData) return false; //fail
DWORD dwcbFullSize = *(DWORD*)(pData + 0xC);
So then if I need to allocated more data, will it be acceptable to call MapViewOfFile
again as such without first unmapping pData
?
BYTE* pFullData = (BYTE*)::MapViewOfFile(hFileMapping,
FILE_MAP_READ, 0, 0, dwcbFullSize);
PS. My goal is not to waste CPU cycles on mapping the entire 32K shared memory segment, when all I may need to read could be way less than that.
Upvotes: 1
Views: 2147
Reputation: 573
There's a chance that I might have misunderstood the question, so please bear with me. I've decided it's easier to show what I was saying in the comments more clearly with some working code. @OP, perhaps from here you can further clarify if this does not address your question(s)?
So I've taken the sample code offered by MSFT and hacked together to demonstrate what I was saying (so the code is essentially MS example code).
https://msdn.microsoft.com/en-us/library/windows/desktop/aa366551(v=vs.85).aspx
You can create a VS Solution with 2 projects, here's the code for project/process 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;
}
Now here's some modified code for the second project/process B. See this for reference: 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;
}
So to answer your question
will it be acceptable to call MapViewOfFile again as such without first unmapping pData?
The example above achieves that. Unless I have misunderstood your query, in which case if you can clarify it'd be great.
Upvotes: 1
Reputation: 33706
for this task need use SEC_RESERVE
attribute when we create file maping(section)
If the file mapping object is backed by the operating system paging file (the hfile parameter is INVALID_HANDLE_VALUE), specifies that when a view of the file is mapped into a process address space, the entire range of pages is reserved for later use by the process rather than committed. Reserved pages can be committed in subsequent calls to the
VirtualAlloc
function. After the pages are committed, they cannot be freed or decommitted with theVirtualFree
function. This attribute has no effect for file mapping objects that are backed by executable image files or data files (the hfile parameter is a handle to a file). SEC_RESERVE cannot be combined with SEC_COMMIT.
so after create section with SEC_RESERVE
attribute need once call MapViewOfFile
- this call not reserve memory range but not commit pages. for commit pages need be call VirtualAlloc
. finally we can free all memory by call 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);
}
}
}
however all this have sense do only for large by size sections. for 32kb(tiny size) the best will be just map all pages in single call
Upvotes: 2