【问题标题】:Transferring data through a memory-mapped file using Win32/WINAPI使用 Win32/WINAPI 通过内存映射文件传输数据
【发布时间】:2014-02-26 16:41:33
【问题描述】:

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

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

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

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

【问题讨论】:

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


    【解决方案1】:

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

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

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

    【讨论】:

    • 出于某种原因,我认为无文件映射总是匿名的。但我想这就是为什么映射本身可以有名称,除了映射文件的名称。无论如何,继承避免了名称冲突的问题。
    • @BenVoigt 是的。无论哪种方式都可以完成。我总是倾向于使用命名对象,但我想这只是我首先学会的技术。
    【解决方案2】:

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

    CreateFileMapping 文档说

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

    但使用 ramdisk 可能更容易。

    【讨论】:

    • Windows 中有 ramdisk 吗?我以为它们是仅限 Linux 的。
    • @sashoalm:有很多第三方软件可以在 Windows 中创建 ramdisk。
    【解决方案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;
    }
    

    【讨论】:

    • 第一个进程中的错误:CopyMemory((PVOID)pBuf, szMsg, (_tcslen(szMsg) * sizeof(TCHAR))); 不复制空终止符 - 替换为 _tcscpy(pBuf, szMsg);memcpy(pBuf, szMsg, sizeof szMsg);
    • 从安全角度来看,命名内存映射文件是个坏主意。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-02-20
    • 2011-04-28
    • 2013-02-17
    • 2016-02-23
    • 2011-01-03
    • 2014-06-22
    • 1970-01-01
    相关资源
    最近更新 更多