Introduction
1.
WIN32 API Functions
Memory-mapped file functions can be thought of
as second cousins to the virtual-memory management functions in Win32.
Like the virtual-memory functions, these functions directly affect a process's
address space and pages of physical memory. No overhead is required to
manage the file views, other than the basic virtual-memory management that
exists for all processes. These functions deal in reserved pages of memory
and committed addresses in a process. The most important of memory-mapped
file functions are:
For more info on Shared Memory techniques and API functions,
please refer to the Microsoft MSDN Library or MSDN
Online
CreateFileMapping
The CreateFileMapping function creates
or opens a named or unnamed file-mapping object for the specified file.
HANDLE CreateFileMapping(
HANDLE hFile, // handle to file
LPSECURITY_ATTRIBUTES lpAttributes, // security
DWORD flProtect, // protection
DWORD dwMaximumSizeHigh, // high-order DWORD of size
DWORD dwMaximumSizeLow, // low-order DWORD of size
LPCTSTR lpName // object name
);
Example (all examples are in C)
hMap = CreateFileMapping(INVALID_HANDLE_VALUE,
NULL,
PAGE_READWRITE,
0,
SizeOf(FlightData),
"SimDataFile")
if (hMap != NULL && GetLastError() == ERROR_ALREADY_EXISTS)
{
CloseHandle(hMap);
hMap = NULL;
}
return hMap;
Explanation
We call the function with INVALID_HANDLE_VALUE which creates
a file-mapping object of the specified size backed by the operating-system
paging file rather than by a named file in the file system
The lpAttributes is set to nil, which means default security,
i.e. the user's security.
flProtect set to PAGE_READWRITE gives read/write access
to the committed region of pages.
dwMaximumSizeHigh and dwMaximumSizeLow should reflect
the size of the file, thus the size of the object RefStruct.
lpName is the name of the file, used in subsequent calls.
After the file is no longer needed, you must close the
handle: CloseHandle(hMap);
MapViewOfFile
The MapViewOfFile function maps a view
of a file into the address space of the calling process.
To specify a suggested base address, use the MapViewOfFileEx
function.
LPVOID MapViewOfFile(
HANDLE hFileMappingObject, // handle to file-mapping object
DWORD dwDesiredAccess, // access mode
DWORD dwFileOffsetHigh, // high-order DWORD of offset
DWORD dwFileOffsetLow, // low-order DWORD of offset
SIZE_T dwNumberOfBytesToMap // number of bytes to map
);
hView = MapViewOfFile(hMap,
FILE_MAP_ALL_ACCESS, 0, 0, 0);
if (hView = NULL)
{
// Error mapping view
}
If dwNumberOfBytesToMap is
set to zero, the entire file is mapped
OpenFileMapping
The OpenFileMapping function opens a named
file-mapping object.
HANDLE OpenFileMapping(
DWORD dwDesiredAccess, // access mode
BOOL bInheritHandle, // inherit flag
LPCTSTR lpName // object name
);
FlightDataMap = OpenFileMapping(FILE_MAP_ALL_ACCESS, false, "SimDataFile")
if (FlightDataMap != NULL)
{
hFlightData = MapViewOfFile(hMap, FILE_MAP_ALL_ACCESS, 0, 0, 0);
if (hFlightData != NULL)
{
// now we have access to the shared memory
}
CloseHandle(FlightDataMap);
}
else
{
// Error opening file mapping
}
UnmapViewOfFile
The UnmapViewOfFile function unmaps a
mapped view of a file from the calling process's address space.
BOOL UnmapViewOfFile( LPCVOIDlpBaseAddress
// starting address);
lpBaseAddress is the pointer to the base address
of the mapped view of a file that is to be unmapped.
This value must be identical to the value returned by
a previous call to the MapViewOfFile or MapViewOfFileEx function.
2.
Defining the structure
As we need a definition to access the different
locations in the mapped file, we typically define a structure.
Things we can put in the structure:
-
values of the flight model (position, acceleration, speed
etc.)
-
values of the different gauges
-
states of all the lights in the cockpit
-
states of all the switches in the cockpit
-
bitmaps of various displays
Depending on the complexity of interaction these values/states
can be read-only or read/write. In the latter case synchronization must
be implemented in the application.
Typically the mapped file contains data which reflect
as many variable states from the sim program as possible.
Example
struct
{
// outputs
float AirSpeed; //
access to airspeed
int LightBits; // access
to lights states (bitwise)
int AutePilot; // access to AutoPilot
switch state
byte LeftMFD[200][200]; // access
to a Multi Function Display
// inputs
float HeadPitch; // Head pitch
of VR helmet
float HeadRoll; // Head roll offset
of VR helmet
float HeadYaw; // Head yaw offset
of VR helmet
} FlightData;
3.
Full example.
These examples are straightforward and should
be able to provide the developer and the user to setup inter-process communication
using shared-memory. I will call the program sharing the data the server.
This is typically the simulation software. Software written to communicate
with the server, I will call the client
construction (server only)
hMap = CreateFileMapping(INVALID_HANDLE_VALUE,
NULL,
PAGE_READWRITE,
0,
SizeOf(FlightData),
"SimDataFile")
if (hMap != NULL && GetLastError() == ERROR_ALREADY_EXISTS)
{
CloseHandle(hMap);
hMap = NULL;
}
destruction (server only)
if (hMap != NULL)
{
CloseHandle(hMap);
hMap = NULL;
}
initialization (client and server)
int init (void)
{
FlightData* FlightData;
HANDLE hFlightData = NULL;
void* FlightDataMap = NULL;
FlightDataMap = OpenFileMapping(FILE_MAP_ALL_ACCESS, false, "SimDataFile")
if (FlightDataMap != NULL)
{
hFlightData = MapViewOfFile(hMap, FILE_MAP_ALL_ACCESS, 0, 0, 0);
if (hFlightData != NULL)
{
FlightData = (FlightData*)hFlightData;
}
{
// do exception handling here
}
}
in process reading and writing (client and server)
// Write internal values to shared memory
FlightData->Airspeed = intAirSpeed;
// Read values from shared memory
intHeadPitch = FlightData->HeadPitch;
destruction (client and server)
int Destroy (void)
{
if (hFlightData)
{
UnmapViewOfFile(hFlightData);
hFlightData = NULL;
}
CloseHandle(FlightDataMap);
}
4.
Conclusion
Using shared memory has great advantages for
sim developers:
-
It gives the ability to expose internal data to 'the outside
world' without the troubles of writing complicated API's.
-
Allows full interaction bases on the presence of data in
the shared memory file.
-
Will allow their products to be used on simulation platforms
and VR devices, thus enhancing the value of the simulation.
If you have any questions or remarks concerning
the use of shared memory or simulation cockpit building in general, feel
free to contact me.
Erwin Neyt (eagle9@simpits.org)
SimPits International
|