使用Win32 / WINAPI通过内存映射文件传输数据

时间:2014-02-26 16:41:34

标签: c++ windows winapi memory-mapped-files

我需要将一些数据 - char buffer[100000]; - 传输到由我启动的子进程。

现在我正在使用普通文件来执行此操作,父进程将数据写入磁盘上的文件,子进程从磁盘读取它并删除该文件。但是,这会导致不必要的磁盘写入,因此我想使用内存映射文件。

如何创建,写入内容映射文件,然后从内存映射文件读取,除非使用页面文件或交换文件,否则不会将数据写入磁盘?

编辑:我忘了指定我想使用原始WINAPI函数,因此代码没有依赖项。我正在研究如何做到这一点,并会在准备好后自己发布答案,但如果有人有现成的代码,我们欢迎他们省下一些努力:)

3 个答案:

答案 0 :(得分:5)

在调用CreateFileMapping时传递INVALID_HANDLE_VALUE作为文件句柄:

  

如果hFile为INVALID_HANDLE_VALUE,则调用进程还必须在dwMaximumSizeHigh和dwMaximumSizeLow参数中指定文件映射对象的大小。在这种情况下,CreateFileMapping创建一个指定大小的文件映射对象,该对象由系统页面文件而不是文件系统中的文件支持。

您可以使用匿名文件映射对象(将可继承句柄传递给子进程),也可以使用命名文件映射。

答案 1 :(得分:3)

我刚刚找到了关于如何操作的an excellent MSDN article,并附上了我在下面粘贴的示例代码。

第一个进程(发送数据):

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

第二个过程(接收数据):

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

答案 2 :(得分:2)

您可以使用句柄继承/句柄复制来使用匿名文件映射(David Heffernan的答案详细介绍此步骤)。例如,在命令行上从父进程传递HANDLE,然后在子进程中使用DuplicateHandle来获取子进程中的有效HANDLE。

CreateFileMapping文档说明

  

多个进程可以通过使用单个共享文件映射对象或创建由同一文件支持的单独文件映射对象来共享同一文件的视图。单个文件映射对象可以由多个进程共享,方法是在创建进程时继承句柄,复制句柄或按名称打开文件映射对象。有关更多信息,请参阅CreateProcess,DuplicateHandle和OpenFileMapping函数。

但是使用ramdisk可能更容易。