Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Transferring data through a memory-mapped file using Win32/WINAPI

I need to transfer some data - char buffer[100000]; - to a child process which is started by me.

Right now I'm using an ordinary file to do so, the parent process writes the data to a file on disk, and the child process reads it from disk and deletes the file. However, that causes unnecessary writes to the disk, so I want to use memory-mapped files instead.

How do I create, write to, and then read from a memory-mapped file in such a way that no data is written to disk, except when the pagefile or swap file is used?

Edit: I forgot to specify that I want to use raw WINAPI functions, so the code doesn't have dependencies. I am researching on how to do it and will post an answer myself when ready, but if someone has ready-made code, they're welcome to save me some effort :)

like image 681
sashoalm Avatar asked Feb 26 '14 16:02

sashoalm


3 Answers

Pass INVALID_HANDLE_VALUE as the file handle when calling CreateFileMapping:

If hFile is INVALID_HANDLE_VALUE, the calling process must also specify a size for the file mapping object in the dwMaximumSizeHigh and dwMaximumSizeLow parameters. In this scenario, CreateFileMapping creates a file mapping object of a specified size that is backed by the system paging file instead of by a file in the file system.

You can use either an anonymous file mapping object (pass inheritable handle to child process), or use a named file mapping.

like image 117
David Heffernan Avatar answered Nov 05 '22 19:11

David Heffernan


You can use an anonymous file mapping (David Heffernan's answer goes into more detail on this step) with handle inheritance / handle duplication. For example, pass the HANDLE from the parent process on the command-line, then in the child use DuplicateHandle to get a valid HANDLE in the child.

The CreateFileMapping documentation says that

Multiple processes can share a view of the same file by either using a single shared file mapping object or creating separate file mapping objects backed by the same file. A single file mapping object can be shared by multiple processes through inheriting the handle at process creation, duplicating the handle, or opening the file mapping object by name. For more information, see the CreateProcess, DuplicateHandle and OpenFileMapping functions.

But it may be easier just to use a ramdisk.

like image 40
Ben Voigt Avatar answered Nov 05 '22 19:11

Ben Voigt


I just found an excellent MSDN article on how to do it, complete with sample code, which I've pasted below.

First process (sends the data):

#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;
}

Second process (receives the data):

#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 _tmain()
{
   HANDLE hMapFile;
   LPCTSTR pBuf;

   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;
   }

   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;
   }

   MessageBox(NULL, pBuf, TEXT("Process2"), MB_OK);

   UnmapViewOfFile(pBuf);

   CloseHandle(hMapFile);

   return 0;
}
like image 3
sashoalm Avatar answered Nov 05 '22 19:11

sashoalm