用户进程看不到服务创建的全局共享内存

jef*_*ffm 2 c++ windows security winapi memory-mapped-files

我有一个 Windows 服务(在系统进程中运行)和一个需要共享配置结构的桌面应用程序。数据源自应用程序,但用户进程无权创建全局内存对象,因此我在服务开始使用 CreateFileMapping() 和基于此答案的 DACL 时创建它。这似乎工作正常:我从 CreateFileMapping() 得到一个非空句柄,GetLastError() 为 0。问题是应用程序看不到对象——OpenFileMapping() 返回一个 NULL 句柄和 ERROR_FILE_NOT_FOUND——如果我使用 WinObj 手动浏览全局对象,我也看不到它。是什么让我的对象不可见?

SECURITY_ATTRIBUTES security;
ZeroMemory(&security, sizeof(security));
security.nLength = sizeof(security);
ConvertStringSecurityDescriptorToSecurityDescriptor(
    "D:P(A;OICI;GA;;;SY)(A;OICI;GA;;;BA)(A;OICI;GWGR;;;IU)",
    SDDL_REVISION_1,
    &security.lpSecurityDescriptor,
    NULL);
HANDLE  hFile = CreateFileMapping(INVALID_HANDLE_VALUE, &security, PAGE_READWRITE, 0, 1024*4, "Global\\gCONFIGXFILE");
DWORD   fileMappingResult = GetLastError();
if (hFile)
{
    CloseHandle(hFile);
}
LocalFree(security.lpSecurityDescriptor);
Run Code Online (Sandbox Code Playgroud)

Rem*_*eau 6

您的服务在创建文件映射后立即关闭其句柄,因此在应用程序有机会打开其映射句柄之前,映射已被销毁。您的服务需要将其映射句柄保持打开状态,至少在应用打开映射句柄之前是这样。

由于您正在共享配置,您可能应该在服务启动时创建映射并将其保持打开状态直到服务停止。您可以使用命名事件 viaCreateEvent()让服务在实际创建映射时通知应用程序,并且可以在任一进程更改映射内容时使用另一个命名事件。

  • 从某种意义上说,关闭句柄*就是*删除。许多内核对象都是引用计数的,包括文件映射。创建映射时,它的引用计数为 1。当您关闭句柄时,其引用计数减少。当引用计数达到零时,映射被释放。这就是为什么应用程序需要在服务关闭其句柄之前打开其映射句柄的原因,因此引用计数不会过早地降至零。 (2认同)