系统错误 0x5:CreateFileMapping()

18

我希望使用命名的共享内存来实现进程间通信(IPC)

为了达成这个目标,其中一步是获取一个句柄到映射内存对象(Mapping Memory Object),使用CreateFileMapping()

我按照MSDN网站的建议进行操作:http://msdn.microsoft.com/en-us/library/aa366551(v=VS.85).aspx

hFileMappingHandle = CreateFileMapping
    (
        INVALID_HANDLE_VALUE,      // use paging file
        NULL,                      // default security 
        PAGE_READWRITE,            // read/write access
        0,            // maximum object size (high-order DWORD) 
        256,            // maximum object size (low-order DWORD)  
        "Global\\MyFileMappingObject"          // name of mapping object
    ); 
DWORD dwError = GetLastError();

然而,返回的句柄始终为0x0,并且返回的系统错误代码为:0x5(访问被拒绝)

  • 仅需要命名内存共享(不需要文件共享)。
  • Windows 7 x64位操作系统
  • 管理员用户权限可用
  • 开发应用程序:64位插件应用程序(.dll)

有人有相同的经验,并有修复此问题的方法吗?我使用MSDN网站作为我的参考,因此我不认为代码存在问题。


不确定这是否是原因,但您需要将最大对象大小设置为内存页的倍数(4096字节)吗? - Eugene Mayevski 'Callback
1
嗨,尤金,不,问题是我没有设置SeCreateGlobalPriviledge。 - Bunkai.Satori
6个回答

13

看起来您没有足够的权限。

来自MSDN:

从会话零以外的会话中在全局命名空间中创建文件映射对象需要SeCreateGlobalPrivilege特权。有关更多信息,请参阅内核对象命名空间。

...

使用CreateFileMapping在全局命名空间中创建文件映射对象,来自会话零以外的会话是一个特权操作。因此,在任意远程桌面会话主机(RD会话主机)服务器会话中运行的应用程序必须启用SeCreateGlobalPrivilege才能成功在全局命名空间中创建文件映射对象。特权检查仅限于文件映射对象的创建,不适用于打开现有对象。例如,如果服务或系统创建了文件映射对象,则任何会话中运行的进程都可以访问该文件映射对象,前提是用户具有必要的访问权限。


5
嗨 Eugene,那正是我的问题。我从我的映射对象名称中删除了前缀“Global\”,显然解决了问题。我暂时不打算处理终端服务,所以这个解决方案应该是可接受的。我阅读了关于SeCreateGlobalPrivilege的文档,但对我来说不太清楚,特别是特权是否可以由应用程序自身分配,还是我需要手动调整特权,比如在 Windows Explorer 中进行操作? - Bunkai.Satori
1
特权是由启动您的应用程序的用户帐户定义的。 您可以尝试使用在此处讨论的AdjustTokenPrivilege函数:http://delphi.about.com/b/2008/09/26/zarko-needs-help-createfilemapping-terminal-services-global-session-secreateglobalprivilege.htm,但这并不能保证结果。 一般来说,请尝试搜索SeCreateGlobalPrivilege,结果包含一些有趣的信息源。 - Eugene Mayevski 'Callback
我删除了前缀“Global\”... 看起来问题解决了。@Bunkai.Satori - 这正是我需要的。谢谢! - Stryker2k2
我删除了前缀“Global\”... 显然这解决了问题。@Bunkai.Satori - 这正是我需要的。谢谢! - undefined

2

默认情况下,管理员、服务和网络服务拥有SeCreateGlobalPrivilege特权。但是请记住,Windows7/Vista不会将所有内容都以管理员身份运行。因此,请使用“以管理员身份启动”来使“Global\”在您的应用程序中起作用。如果您正在调试,请也以管理员身份启动Visual Studio。


非常感谢!在Windows 10下,Visual Studio默认不是管理员权限。这就是我的问题所在。 - Gabe Halsmer
如果我们想为没有管理员权限的用户使用CreateFileMapping,我们该怎么做? - Ganesh Kamath - 'Code Frenzy'

1
要创建全局文件映射,您需要具有SeCreateGlobalPrivilege特权 - 您是否拥有该特权?访问被拒绝意味着这是一个权限问题,肯定是这样的。

嗨Steve,那就是我的问题。谢谢。我现在用了不同的方法解决了这个问题,但是如果我想在应用程序内编程设置权限,可以吗? - Bunkai.Satori
您可以使用AdjustTokenPrivileges来完成此操作,如下所示:http://msdn.microsoft.com/en-us/library/aa446619(v=VS.85).aspx。令牌句柄来自于`OpenProcessToken`,必须使用(至少)`TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY`进行调用。 - Steve Townsend

0

使用安全属性和DACL。 示例:

ZeroMemory(&attributes, sizeof(attributes));
attributes.nLength = sizeof(attributes);
ConvertStringSecurityDescriptorToSecurityDescriptorA(
            "D:P(A;OICI;GA;;;SY)(A;OICI;GA;;;BA)(A;OICI;GWGR;;;IU)",
            SDDL_REVISION_1,
            &attributes.lpSecurityDescriptor,
            NULL);
hMapObject = CreateFileMappingA(
            INVALID_HANDLE_VALUE,
            &attributes,
            PAGE_READWRITE,
            0,
            1024,
            "mySMobject");

0

关于全局命名空间的文档中提到终端服务有点误导,因为它暗示你只需要在出现异常情况时才需要担心这个问题。

实际上,IIS和系统服务都在零会话中运行,第一个/唯一登录的用户在1号会话中运行 - 因此您必须使用全局命名空间来在IIS或服务与普通程序之间进行通信。


0

这是一个非常古老的问题,已经被标记为已回答。但是通过阅读同一篇MSDN文章并基于它构建一个示例,我能够成功地完成而不需要任何特殊权限。

只需要摆脱名称中的“Global\”部分即可。令人惊讶的是,对于信号量和事件,这种方式不起作用,您将收到“0x2 ERROR_FILE_NOT_FOUND”的错误。但是对于内存映射共享内存它完全有效。我能够在服务器上创建一个读/写共享内存,并在客户端上打开它。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接