后台:我正在尝试创建一个可由多个进程访问的内存映射文件。在下面的代码中,我只输入了与我目前的问题有关的代码,使事情更简单。根据msdn我应该能够创建一个文件映射,映射文件的视图并关闭我从CreateFileMapping收到的句柄,MapViewOfFile将保持我的FileMap活着。在我UnmapViewOfFile之前,FileMap仍然可以访问。
MSDN: CreateFileMapping function
文件映射对象的映射视图维护对该对象的内部引用,并且在释放对它的所有引用之前,文件映射对象不会关闭。因此,要完全关闭文件映射对象,应用程序必须通过调用UnmapViewOfFile取消映射文件映射对象的所有映射视图,并通过调用CloseHandle来关闭文件映射对象句柄。可以按任何顺序调用这些函数。
问题:成功映射文件视图然后关闭CreateFileMapping收到的句柄后,FileMap不再存在(它应该仍然存在),我的MemMapFileReader能够创建一个新的地图误差为0.(当它应该是接收错误183'已存在'时)
错误解决方案:不关闭句柄允许MemMapFileReader程序访问它,但会导致MemMapFileCreator中的句柄泄漏,因为在关闭进程之前句柄永远不会关闭。
问题:我错过了什么或做错了什么?
MemMapFileCreator
#include "stdafx.h"
#include <windows.h>
#include <stdio.h>
#include <conio.h>
#include <tchar.h>
#include <iostream>
#define BUF_SIZE 256
TCHAR szName[] = TEXT("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
DWORD lastError = GetLastError();
if (hMapFile == NULL)
{
_tprintf(TEXT("Could not create file mapping object (%d).\n"),
GetLastError());
std::cin.get();
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);
std::cin.get();
return 1;
}
CopyMemory((PVOID)pBuf, szMsg, (_tcslen(szMsg) * sizeof(TCHAR)));
CloseHandle(hMapFile);
_getch();
UnmapViewOfFile(pBuf);
return 0;
}
MemMapFileReader
#include "stdafx.h"
#include <windows.h>
#include <stdio.h>
#include <conio.h>
#include <tchar.h>
#include <iostream>
#pragma comment(lib, "user32.lib")
#define BUF_SIZE 256
TCHAR szName[] = TEXT("MyFileMappingObject");
int _tmain()
{
HANDLE hMapFile;
LPCTSTR pBuf;
hMapFile = CreateFileMapping(
INVALID_HANDLE_VALUE,
NULL,
PAGE_READWRITE, // read/write access
0,
BUF_SIZE,
szName); // name of mapping object
DWORD lastError = GetLastError();
if (hMapFile == NULL)
{
_tprintf(TEXT("Could not open file mapping object (%d).\n"),
GetLastError());
std::cin.get();
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);
std::cin.get();
return 1;
}
MessageBox(NULL, pBuf, TEXT("Process2"), MB_OK);
UnmapViewOfFile(pBuf);
CloseHandle(hMapFile);
std::cin.get();
return 0;
}
答案 0 :(得分:4)
来自MSDN:
文件映射对象的映射视图维护对该对象的内部引用,并且在释放对它的所有引用之前,文件映射对象不会关闭。因此,要完全关闭文件映射对象,应用程序必须通过调用UnmapViewOfFile取消映射文件映射对象的所有映射视图,并通过调用CloseHandle来关闭文件映射对象句柄。可以按任何顺序调用这些函数。
CreateFileMapping文档说明要完全关闭文件,必须关闭所有句柄,顺序无关紧要。这个逻辑是不可逆的:你不能关闭一个句柄,并期望使用其他句柄,就像文件映射没有“关闭”一样。
换句话说,这意味着要清理文件映射,您需要以任何顺序关闭所有句柄。但是,您无法关闭基础文件映射对象,仍然使用依赖于它的视图。
答案 1 :(得分:2)
文件映射对象的映射视图将内部引用维护到对象,并且文件映射对象在释放所有对它的引用之前不会关闭。
CloseHandle()
文档说:
通常, CloseHandle使指定的对象句柄无效,减少对象的句柄计数,并执行对象保留检查。关闭对象的最后一个句柄后,将从系统中删除该对象。
映射视图只是将映射对象的引用计数保持在零以上,直到它们被取消映射,但它们不会使底层文件/映射本身保持打开状态。
答案 2 :(得分:0)
关闭之后创建者进程中的节句柄视图不会消失,直到取消它的名称 - &#34; MyFileMappingObject&#34;在NT命名空间中被销毁。结果接下来调用CreateFileMapping - 找不到命名对象&#34; MyFileMappingObject&#34;并创建新的(当您的逻辑打开现有时)。再次 - 部分没有被摧毁,但它的名字被摧毁了。 你的名字 - 坏的解决方案 - 真的不错 - 这是绝对正常的 - 你没有关闭部分的句柄。这不是手柄泄漏 - 只需在您的过程中永久打开手柄。这种情况绝对正常
你使用的是NAMED部分。关闭后它处理 - 部分没有被破坏 - 因为存在部分的视图,它持有它。但部分的名称是DESTROYED。和新创建部分的调用 - 不打开现有但创建新部分。
答案 3 :(得分:0)
存在其他一个解决方案,这表明你们都错了。 它需要SE_CREATE_PERMANENT_PRIVILEGE,但对于演示这是正常的
STATIC_OBJECT_ATTRIBUTES_EX(g_oa, "\\BaseNamedObjects\\MyFileMappingObject", OBJ_CASE_INSENSITIVE|OBJ_PERMANENT, 0, 0);
NTSTATUS CreateAndWrite()
{
NTSTATUS status;
HANDLE hSection;
LARGE_INTEGER Size = { PAGE_SIZE };
if (0 <= (status = ZwCreateSection(&hSection, SECTION_MAP_READ|SECTION_MAP_WRITE, &g_oa, &Size, PAGE_READWRITE, SEC_COMMIT, 0)))
{
PVOID BaseAddress = 0;
SIZE_T ViewSize = 0;
if (0 <= (status = ZwMapViewOfSection(hSection, NtCurrentProcess(), &BaseAddress, 0, 0, 0, &ViewSize, ViewUnmap, 0, PAGE_READWRITE)))
{
STATIC_WSTRING(szMsg, "Message from first process.");
memcpy(BaseAddress, szMsg, sizeof(szMsg));
ZwUnmapViewOfSection(NtCurrentProcess(), BaseAddress);
}
ZwClose(hSection);
}
return status;
}
NTSTATUS OpenReadAndDestroy()
{
NTSTATUS status;
HANDLE hSection;
if (0 <= (status = ZwOpenSection(&hSection, SECTION_MAP_READ|DELETE, &g_oa)))
{
PVOID BaseAddress = 0;
SIZE_T ViewSize = 0;
if (0 <= (status = ZwMapViewOfSection(hSection, NtCurrentProcess(), &BaseAddress, 0, 0, 0, &ViewSize, ViewUnmap, 0, PAGE_READONLY)))
{
MessageBox(0, (PCWSTR)BaseAddress, 0, 0);
ZwUnmapViewOfSection(NtCurrentProcess(), BaseAddress);
}
ZwMakeTemporaryObject(hSection);
ZwClose(hSection);
}
return status;
}
if (0 <= GotPermanentPrivilege())
{
if (0 <= CreateAndWrite())
{
// at this point - no one handles for "MyFileMappingObject" exist
// we close all and even unmap view
// but 1 reference to section object exist (by OBJ_PERMANENT flag)
// and NAME is still exist
// as result we can open,map and read data :)
OpenReadAndDestroy();
}
}
你怎么说的?
所有句柄关闭后,部分被销毁?不能使用意见? d)
P.S。 SE_CREATE_PERMANENT_PRIVILEGE - 通常只有LocalSystem,但我们可以得到它,如果有SE_DEBUG_PRIVILEGE + SE_IMPERSONATE_PRIVILEGE - 打开&#34; system&#34;线程并模仿它