共享命名对象

本主题介绍如何在打包的桌面应用(包括使用 MSIX 打包的Windows 应用 SDK应用)和未打包的 Win32 应用程序之间共享命名对象。

打包应用程序中的命名对象

命名对象 为进程提供共享对象句柄的简单方法。 进程创建命名对象后,其他进程可以使用该名称调用相应的函数来打开对象的句柄。 命名对象通常用于 线程同步进程间通信

默认情况下,在 AppContainer(如 UWP 应用)中运行的应用程序具有独立的命名对象命名空间 ,它们只能访问他们创建的命名对象。 完全信任打包的桌面应用(包括Windows 应用 SDK应用)没有这种隔离,并在全局命名空间中创建命名对象。 有关详细信息,请参阅Windows 应用 SDK注意事项

若要与 AppContainer 应用共享命名对象,必须在创建对象时设置权限,并在打开对象时必须限定名称。 当你想要限制任意进程之间的访问时,无论是否打包,本文介绍的技术也同样适用。

创建命名对象

命名对象是使用相应的 Create API 创建的:

所有这些 API 共享一个 LPSECURITY_ATTRIBUTES 参数,使调用方能够指定 访问控制列表(ACL), 以控制哪些进程可以访问该对象。 若要与打包的应用程序共享命名对象,必须在创建命名对象时在 ACL 中授予权限。

安全标识符(SID)表示 ACL 中的标识。 每个打包的应用程序都有自己的 SID,具体取决于其包系列名称。 可以通过将其包系列名称传递给 DeriveAppContainerSidFromAppContainerName,为打包的应用程序生成 SID。

注释

包系列名称可通过开发期间Visual Studio中的包清单编辑器、通过合作伙伴中心查找通过 Microsoft Store 发布的应用程序,或通过已安装应用程序的 Get-AppxPackage PowerShell 命令找到。

此示例 演示了 ACL 命名对象所需的基本模式。 若要与打包的应用程序共享命名对象,请为每个应用程序生成 EXPLICIT_ACCESS 结构:

通过在 Create 调用中使用适用于打包应用程序的 EXPLICIT_ACCESS 规则填充 LPSECURITY_ATTRIBUTES 参数,可以授予这些应用程序打开该命名对象的访问权限。

注释

如果该对象的 DACL 允许此类访问,则 Win32 应用程序可以在 打开这些对象 时通过限定对象名称来访问由 AppContainer 应用创建的命名对象。 大多数命名对象的默认 DACL 授予对创建者和管理员的访问权限。 如果已设置限制性 DACL,则 Win32 调用方还需要显式访问条目。

示例:使用 ACL 创建命名事件(C++)

以下示例演示如何创建命名事件并授予对打包应用程序的访问权限:

#include <windows.h>
#include <sddl.h>
#include <aclapi.h>
#include <userenv.h>

HANDLE CreateSharedEvent(PCWSTR eventName, PCWSTR packageFamilyName)
{
    // Derive the SID for the target packaged application
    PSID appContainerSid = nullptr;
    HRESULT hr = DeriveAppContainerSidFromAppContainerName(
        packageFamilyName, &appContainerSid);
    if (FAILED(hr)) return nullptr;

    // Build an EXPLICIT_ACCESS entry granting synchronization and signal rights
    EXPLICIT_ACCESS_W explicitAccess = {};
    explicitAccess.grfAccessPermissions = SYNCHRONIZE | EVENT_MODIFY_STATE;
    explicitAccess.grfAccessMode = GRANT_ACCESS;
    explicitAccess.grfInheritance = NO_INHERITANCE;
    explicitAccess.Trustee.TrusteeForm = TRUSTEE_IS_SID;
    explicitAccess.Trustee.TrusteeType = TRUSTEE_IS_USER;
    explicitAccess.Trustee.ptstrName = reinterpret_cast<LPWSTR>(appContainerSid);

    // Create the ACL
    PACL acl = nullptr;
    DWORD result = SetEntriesInAclW(1, &explicitAccess, nullptr, &acl);
    if (result != ERROR_SUCCESS)
    {
        FreeSid(appContainerSid);
        return nullptr;
    }

    // Create the security descriptor
    SECURITY_DESCRIPTOR sd = {};
    if (!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION) ||
        !SetSecurityDescriptorDacl(&sd, TRUE, acl, FALSE))
    {
        LocalFree(acl);
        FreeSid(appContainerSid);
        return nullptr;
    }

    SECURITY_ATTRIBUTES sa = {};
    sa.nLength = sizeof(sa);
    sa.lpSecurityDescriptor = &sd;
    sa.bInheritHandle = FALSE;

    // Create the named event with only the rights the creator needs
    HANDLE hEvent = CreateEventExW(&sa, eventName, 0,
        SYNCHRONIZE | EVENT_MODIFY_STATE);

    // Cleanup
    LocalFree(acl);
    FreeSid(appContainerSid);

    return hEvent;
}

打开命名对象

命名对象通过向相应的 Open API 传递名称来打开:

打包应用程序创建的命名对象是在应用程序的命名空间中创建的,否则称为命名对象路径。 打开由打包应用程序创建的命名对象时,对象名称必须以创建应用程序的命名对象路径为前缀。

GetAppContainerNamedObjectPath 基于其 SID 返回打包应用程序的命名对象路径。 可以通过将其包系列名称传递给 DeriveAppContainerSidFromAppContainerName,为打包的应用程序生成 SID。

注释

包系列名称可通过开发期间Visual Studio中的包清单编辑器、通过合作伙伴中心查找通过 Microsoft Store 发布的应用程序,或通过已安装应用程序的 Get-AppxPackage PowerShell 命令找到。

打开由打包的应用程序创建的命名对象时,请使用以下格式 <PATH>\<NAME>

  • 用创建应用程序的命名对象路径替换 <PATH>
  • 用对象名称替换 <NAME>

注释

仅当打包的应用程序创建了对象时,才需要为 <PATH> 对象名称添加前缀。 Win32 应用程序创建的命名对象不需要限定,但创建对象时仍必须授予访问权限。

Windows 应用 SDK 注意事项

Windows 应用 SDK使用 MSIX 打包的桌面应用以包标识的完全信任进程的形式运行, 它们不会在 AppContainer 中运行。 这意味着其命名对象默认在全局命名空间中创建,就像传统的 Win32 应用程序一样。

但是,在以下场景中,你仍然需要采用上文所述的 ACL 和路径限定流程:

  • 与 UWP 应用通信 — UWP 应用在 AppContainer 中运行,并具有独立的命名对象命名空间。 使用 GetAppContainerNamedObjectPath,并通过 ACL 授予访问权限,以访问 UWP 应用的命名对象。
  • 限制访问 - 即使在完全信任应用之间,你可能希望使用显式 ACL 来限制哪些进程可以打开命名对象。
  • 解压缩Windows 应用 SDK应用 — 命名对象位于全局命名空间中,无需特殊处理,与传统 Win32 应用程序相同。

Remarks

默认情况下,打包应用中的命名对象会被隔离,以维护安全性,并确保支持应用程序挂起和终止等生命周期事件。 跨应用程序共享命名对象会引入严格的绑定和版本控制约束,并且要求每个应用程序对其他应用程序的生命周期具有复原能力。 出于这些原因,建议仅在同一发布服务器的应用程序之间共享命名对象。