共用方式為


Windows 應用程式中套件身分識別的概觀

套件身分識別 是跨空間和時間的唯一標識符。 就像您的 DNA 可唯一識別您一樣,套件識別可唯一識別套件。

套件有一組相關的資料(如檔案等)。 沒有兩個套件具有相同的身分識別,而且任何與套件相關的位元變更都需要不同的身分識別。

什麼是套件身分識別?

套件識別 是一種邏輯構造,能唯一識別一個套件。 身分識別有5個部分:

  • 名字: 這是應用程式開發人員選擇的名稱。 Microsoft 市集確保所有市集內應用程式開發者的應用程式名稱是唯一的,但不保證在整體生態體系中名稱也是唯一的。
  • 版本: 套件的版本號碼。 應用程式開發人員可以選擇任意版本號碼,但必須確保版本號碼隨著更新而增加。
  • 架構: 封裝針對的處理器架構。 相同的應用程式可以建置以不同的處理器架構為目標,每個組建都位於自己的套件中。
  • ResourceId: 應用程式開發人員選擇用來唯一識別資源套件的字串,例如不同語言或不同的顯示縮放比例。 資源套件通常是架構中性套件。 對於套件,ResourceId 一律為 ~
  • Publisher: 應用程式開發人員的主體名稱,由其簽署憑證所識別。 這在理論上對每個應用程式開發人員而言都是唯一的,因為信譽良好的證書頒發機構單位會使用唯一的實際名稱和身分識別來填入憑證的主體名稱欄位。

此建構有時被稱為 的 5元組

備註

未簽署的套件 (1) 仍然需要 Publisher,(2) Publisher 必須包含未簽署標記 (OID.2.25.311729368913984317654407730594956997722=1),(3) 未簽署標記 必須是 Publisher 字符串中的最後一個字段,而且 (4) 沒有未簽署套件的憑證或簽署。

套件識別字段限制

領域 數據類型 限制 評論
名稱 封裝字串 最小值:3
最大值:50
每個驗證 API 允許的值(請參閱 套件字串
版本 DotQuad 最小值:0.0.0.0
最大值:65535.65535.65535.65535
字串格式使用十進位制的點表示法,『Major.Minor.Build.Revision』
建築 枚舉 最小值:N/A
最大值:N/A
允許的值為 “neutral”、“x86”、“x64”、“arm”、“arm64”、“x86a64”
資源識別碼 (ResourceId) 封裝字串 最小值:0
最大值:30
每個驗證 API 允許的值(請參閱 套件字串
發行人 繩子 最小值:1
最大值:8192
根據 X.509 標準允許的值
PublisherId(出版商識別碼) 繩子 最小值:13
最大值:13
Base32 編碼,Crockford 變體,即 [a-hjkmnp-tv-z0-9]

什麼是「套件字串」?

套件字串 是允許下列字元的字串:

  • 允許輸入字元 (ASCII 子集)
    • 大寫字母(U+0041 至 U+005A)
    • 小寫字母 (U+0061 到 U+007A)
    • 數字(U+0030 到 U+0039)
    • 點(U+002E)
    • 破折號 (U+002D)

禁止使用下列值做為封裝字串:

狀況 禁止的值
不能等於 “.”、“..”、“con”、“prn”、“aux”、“nul”、“com1”、“com2”、“com3”、“com4”、“com5”、“com6”、“com7”、“com8”、“com9”、“lpt1”、“lpt2”、“lpt3”、“lpt4”、“lpt5”、“lpt6”、“lpt7”、“lpt8”、“lpt9”
無法以...開頭 “con.”、“prn.”、“aux.”、“nul.”、“com1.”、“com2.”、“com3.”、“com4.”、“com5.”、“com6.”、“com7.”、“com8.”、“com9.”、“lpt1.”、“lpt2.”、“lpt3.”、“lpt4.”、“lpt5.”、“lpt6.”、“lpt7.”、“lpt8.”、“lpt9.”、“xn--”
不能以 結尾 "."
不能包含 “.xn--”

必須使用不區分大小寫的字串比較 API 來比較 套件字串(例如_wcsicmp)。

套件身分識別的 nameresourceid 欄位是套件字串。

PackageId 物件

PackageId 是一個物件,其中包含作為個別欄位的 5 部分元組(NameVersionArchitectureResourceIdPublisher)。

套件完整名稱

套件完整名稱 是一個不透明的字串,由套件身分識別的五個部分(名稱、版本、架構、資源ID、發行者)衍生而來。

<Name>_<Version>_<Architecture>_<ResourceId>_<PublisherId>

例如,Windows 相片應用程式的一個套件完整名稱是 「Microsoft.Windows.Photos_2020.20090.1002.0_x64__8wekyb3d8bbwe」, 其中 「Microsoft.Windows.Photos」 是名稱,“2020.20090.1002.0” 是版本號碼,“x64” 是目標處理器架構,資源標識符是空的(最後兩個底線之間沒有內容),而 “8wekyb3d8bbwe” 是Microsoft的發行者標識符。

套件完整名稱 可唯一識別 MSIX 套件或套件組合。 有兩個包或組合包的內容不同,但具有相同的完整名稱是錯誤的。

備註

MSIX 是上一個字詞的新名稱,APPX。 如需詳細資訊,請參閱 什麼是 MSIX?

套件系列名稱

套件系列名稱 是一個不透明的字串,僅由套件識別中的兩個部分構成 - 名稱發行者

<Name>_<PublisherId>

例如,Windows 相片應用程式的套件系列名稱是 “Microsoft.Windows.Photos_8wekyb3d8bbwe”,其中 “Microsoft.Windows.Photos” 是名稱,而 “8wekyb3d8bbwe” 是Microsoft的發行者標識符。

套件系列名稱通常稱為「無版本套件完整名稱」。

備註

這不完全正確,因為套件系列名稱也缺少架構和資源 ID。

備註

數據和安全性通常會限定於套件系列。 例如,若您將從 Notepad 1.0.0.0 版套件安裝的記事本應用程式設定為啟用自動換行,可能會帶來不佳的使用體驗。 接著,記事本會更新為 1.0.0.1,而且您的設定數據不會延續至較新版本的套件。

發行者標識碼

套件系列名稱是格式如下的字串:

<name>_<publisherid>

其中發行者標識碼具有一些非常特定的屬性:

  • 衍生自發行者
  • MinLength = MaxLength = 13 個字元 [固定大小]
  • 允許的字元 (如 regex) = a-hj-km-np-tv-z0-9
    • Base-32, Crockford Variant, 即英數位元 (A-Z0-9) 除了沒有 I (眼睛), L (ell), O (哦) 或 U (你)
  • 比較時忽略順序的大小寫:ABCDEFABCDEFG == abcdefabcdefg

所以你永遠不會看到 %: \ / “ ? 或發行者標識碼中的其他字元。

如需詳細資訊,請參閱 PackageFamilyNameFromIdPackageNameAndPublisherIdFromFamilyName

發行者標識碼通常稱為 PublisherId。

為什麼發行者標識碼存在?

發行者 ID 之所以存在,是因為發行者必須與您的憑證的 X.509 名稱/簽署者匹配,因此:

  • 它可以非常大(長度 <= 8192 個字元)
  • 它可以包含不常見或受限的字元(例如反斜杠等)

這些問題可能會讓某些 X.509 字串變得尷尬或無法在文件系統、登錄、URL 和其他內容中使用。

如何建立 PublisherId?

使用 PackageNameAndPublisherIdFromFamilyName 來從 PublisherId中擷取 PackageFamilyName

使用 PackageIdFromFullName,從 PublisherId取得 PackageFullName

很少需要從 PublisherId建立 Publisher ,但可以使用可用的 API 來完成:

#include <appmodel.h>

HRESULT PublisherIdFromPublisher(
    _In_ PCWSTR publisher,
    _Out_writes_(PACKAGE_PUBLISHERID_MAX_LENGTH + 1) PWSTR publisherId)
{
    PCWSTR name{ L"xyz" };
    const size_t nameLength{ ARRAYSIZE(L"xyz") - 1 };
    const size_t offsetToPublisherId{ name + 1 }; // xyz_...publisherid...
    PACKAGE_ID id{};
    id.name = name;
    id.publisher = publisher;
 
    WCHAR familyName[PACKAGE_PUBLISHERID_MAX_LENGTH + 1]{};
    UINT32 n{ ARRAYSIZE(familyName) };
    RETURN_IF_WIN32_ERROR(PackageFamilyNameFromId(&id, &n, familyName);
    RETURN_IF_FAILED(StringCchCopyW(publisherId, PACKAGE_PUBLISHERID_MAX_LENGTH + 1, familyName + offsetToPublisherId));
    return S_OK;
}

以下是相同作業的傳統 Windows C 實作:

#include <appmodel.h>

HRESULT PublisherIdFromPublisher(
    _In_ PCWSTR publisher,
    _Out_writes_(PACKAGE_PUBLISHERID_MAX_LENGTH + 1) PWSTR publisherId)
{
    const WCHAR c_name[]{ L"xyz" };
    const UINT32 c_nameLength{ ARRAYSIZE(c_nameForPublisherToPublisherId) - 1 };

    PACKAGE_ID id{};
    id.name = c_name;
    id.publisher = publisher;
    WCHAR familyName[PACKAGE_PUBLISHERID_MAX_LENGTH + 1]{};
    UINT32 n{ ARRAYSIZE(familyName) };
    RETURN_IF_WIN32_ERROR(PackageFamilyNameFromId(&id, &n, familyName));
    RETURN_IF_FAILED(StringCchCopyW(publisherId, PACKAGE_PUBLISHERID_MAX_LENGTH + 1,  familyName + c_nameLength + 1);
    return S_OK;
}

藉由將套件 ID 轉換為套件系列名稱,建立的 PublisherId 即為格式 xyz_<publisherid>。 這個食譜是穩定和可靠的。

這只需要從 SDK 使用 appmodel.h 進行編譯,並連結至 kernel32.lib;若使用 APIsets,則選用 kernelbase.lib、onecore.lib 或 api-ms-win-appmodel-runtime-l1.lib。

瞭解套件身分識別中的處理器架構

常見的誤解是表示 Architecture=x64 套件只能包含 x64 程式代碼。 這不是真的。 這表示套件適用於支援 x64 程式代碼的系統,而且可供 x64 應用程式使用。 您可以只製作包含 PDF 檔案的套件,但使用 宣告它 <Identity Architecture=x64...> ,因為它只打算安裝在 x64 相容系統上(例如 x64 套件只能安裝在 x64 和 (從 Windows 11 起)Arm64 系統,因為 x86、Arm 和 Windows 10 Arm64 系統不支援 x64。

更誤解的是,Architecture=neutral 不會 表示套件不包含可執行程式碼。 這表示套件適用於所有架構。 例如,您可以建立一個套件,包含使用 JavaScript、Python、C# 等語言撰寫的 AES 加密 API,但在 Arm64 系統上的效能不夠理想。 因此,您會包含優化的 Arm64 二進位檔,並實作 API 來處理它:

void Encrypt(...)
{
    HANDLE h{};
    if (GetCpu() == arm64)
    {
        h = LoadLibrary(GetCurrentPackagePath() + "\bin\encrypt-arm64.dll")
        p = GetProcAddress(h, "Encrypt")
        return (*p)(...)
    }
    else
    {
        // ...call other implementation...
    }
}

或者,您可以建立具有多個變體的中性套件:

\
    bin\
        encrypt-x86.dll
        encrypt-x64.dll
        encrypt-arm.dll
        encrypt-arm64.dll

開發人員接著可以在運行時間 LoadLibrary("bin\encrypt-" + cpu + ".dll") 取得其程序的適當二進位檔。

一般而言,中性套件沒有個別架構的內容,但也可能有。 有些事情有其限制(例如,您可以製作一個記事本套件,其中包含針對 x86 + x64 + arm + arm64 編譯的 notepad.exe,但 appxmanifest.xml 只能宣告指向其中之一的 <Application Executable=...>)。 考慮到有些套件組合能讓您只安裝所需的部件,這種做法是非常少見的。 這不是非法的,只是先進且不同尋常。

此外, Architecture=x86 (或 x64|arm|arm64) 並不表示套件只包含指定架構的可執行程序代碼。 這只是非常普遍的情況。

備註

在此內容中討論「程序代碼」或「可執行程式代碼」時,我們指的是可攜式可執行檔 (PE) 檔案。

套件身分識別是否區分大小寫?

大部分情形下,不,但 Publisher 區分大小寫。

其餘欄位 (NameResourceIdPublisherIdPackageFullNamePackageFamilyName) 不是。 這些欄位會保留字母的大小寫,但在比較時不區分大小寫。

另請參閱

套件識別

PackageFamilyNameFromId

PackageNameAndPublisherIdFromFamilyName