本主題說明如何在已打包的桌面應用程式(包括以 MSIX 打包的 Windows 應用程式 SDK 應用程式)與未封裝的 Win32 應用程式之間共享命名物件。
封裝應用程式中的命名物件
命名物件 為程序提供一種簡單的方式來共享物件句柄。 當程序建立一個命名物件後,其他程序可以使用該名稱呼叫適當的函式,以開啟該物件的句柄。 命名物件通常用於 執行緒同步 與 程序間通訊。
在 AppContainer 中執行的應用程式(例如 UWP 應用程式)預設有獨立的命名物件命名空間——它們只能存取自己建立的命名物件。 全信任封裝的桌面應用程式(包括 Windows 應用程式 SDK 應用程式)沒有這種隔離,會在全域命名空間中建立命名物件。 詳情請參閱 Windows 應用程式 SDK 考量。
要與 AppContainer 應用程式分享命名物件,建立物件時必須設定權限,開啟物件時必須先限定名稱。 本文中的技巧在你想限制任何流程間的存取時也很有用,無論包裝為何。
建立命名物件
命名物件會以對應 Create 的 API 建立:
所有這些 API 共享一個 LPSECURITY_ATTRIBUTES 參數,讓呼叫者能指定 存取控制清單(ACL), 以控制哪些程序可以存取該物件。 為了與封裝應用程式共享命名物件,必須在建立命名物件時,透過 ACL 授權。
安全識別碼(SID)代表 ACL 中的身份。 每個封裝應用程式都有一個以其套件家族名稱為基礎的 SID。 你可以透過將套件族名稱傳給 DeriveAppContainerSidFromAppContainerName 來產生已封裝應用程式的 SID。
Note
套件名稱可在開發期間透過 Visual Studio 的套件清單編輯器找到,或透過 Microsoft Store 發佈的應用程式透過 Partner Center 找到,或透過 Get-AppxPackage PowerShell 指令(已安裝的應用程式)找到。
此範例 展示了對命名物件進行 ACL 的基本模式。 要與已封裝的應用程式分享命名物件,請為每個應用程式建立 一個EXPLICIT_ACCESS 結構:
grfAccessMode = GRANT_ACCESS-
grfAccessPermissions =根據物件及預期使用方式適當授權 grfInheritance = NO_INHERITANCETrustee.TrusteeForm = TRUSTEE_IS_SIDTrustee.TrusteeType = TRUSTEE_IS_USER-
Trustee.ptstrName =SID 是從 DeriveAppContainerSidFromAppContainerName 取得的
透過在 Create 呼叫中使用 EXPLICIT_ACCESS 的封裝應用程式規則來填入 LPSECURITY_ATTRIBUTES 參數,你可以授與這些應用程式開啟具名物件的存取權。
Note
Win32 應用程式可在 開啟物件時限定物件名稱,且物件的 DACL 允許存取,即可存取由 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。
Note
套件名稱可在開發期間透過 Visual Studio 的套件清單編輯器找到,或透過 Microsoft Store 發佈的應用程式透過 Partner Center 找到,或透過 Get-AppxPackage PowerShell 指令(已安裝的應用程式)找到。
當打開由已封裝應用程式建立的命名物件時,請使用以下格式 <PATH>\<NAME>:
- 以建立該物件之應用程式的具名物件路徑取代
<PATH>。 - 用物件名稱替換
<NAME>。
Note
只有當已封裝的應用程式創建了物件時,才需要在物件名稱 <PATH> 前加上前綴。 由 Win32 應用程式建立的命名物件不需要經過限定,但物件 建立時仍需授權存取權限。
Windows 應用程式 SDK 注意事項
Windows 應用程式 SDK 桌面應用程式與 MSIX 一起打包,會以全信任程序的形式執行,並帶有套件身份——它們不會在 AppContainer 中執行。 這表示它們的命名物件預設是在全域命名空間中建立,就像傳統的 Win32 應用程式一樣。
然而,在以下情況中,您仍需要上述 ACL 和路徑限定程序:
-
與 UWP 應用程式通訊 — UWP 應用程式運行於 AppContainer 中,並擁有隔離的命名物件命名空間。 使用
GetAppContainerNamedObjectPath並透過 ACL 授與存取權限,以存取 UWP 應用程式的具名物件。 - 限制存取 權限 — 即使在完全信任的應用程式間,你也可能想使用明確的 ACL 來限制哪些程序可以開啟你指定的物件。
- 未封裝的 Windows 應用程式 SDK 應用程式 — 命名物件位於全域命名空間中,無需特殊處理,與傳統 Win32 應用程式相同。
Remarks
封裝應用程式中的命名物件預設會被隔離,以維護安全性並確保支援應用程式生命週期事件,如暫停與終止。 在不同應用程式間共享命名物件會引入嚴格的綁定與版本限制,並要求每個應用程式對其他應用程式的生命週期具備彈性。 因此,建議只在同一出版商的應用程式間共享命名物件。