Windows アプリのパッケージ ID の概要

パッケージ ID は、空間と時間を越えた一意の識別子です。 人が DNA によって一意に識別されるのと同様に、パッケージ ID によってパッケージが一意に識別されます。

パッケージには、ビット (ファイルなど) のセットが関連付けられています。 2 つのパッケージに同じ ID があることはなく、パッケージに関連するビットを変更する場合は、別の ID が必要になります。

パッケージ ID とは

パッケージ ID は、パッケージを一意に識別する論理コンストラクトです。 この ID は、次の 5 つの部分から成ります。

  • 名前: これは、アプリ開発者が選択した名前です。 Microsoft Store は、Microsoft Store 内のすべてのアプリ開発者に対してすべてのアプリ名が一意になるように強制していますが、名前が必ずしも一般的なエコシステムで一意であるとは限りません。
  • バージョン: パッケージのバージョン番号。 アプリ開発者は任意のバージョン番号を選択できますが、更新プログラムによってバージョン番号が上がることを確認する必要があります。
  • アーキテクチャ: パッケージの対象となるプロセッサ アーキテクチャ。 同じアプリは、異なるプロセッサ アーキテクチャを対象としてビルドでき、各ビルドは独自のパッケージに存在します。
  • ResourceId: さまざまな言語や異なる表示スケールなど、リソース パッケージを一意に識別するためにアプリ開発者が選択した文字列。 リソース パッケージは通常、アーキテクチャに依存しません。 バンドルの場合、ResourceId は常に ~ です。
  • 公開元: アプリ開発者の署名証明書によって識別されるアプリ開発者のサブジェクト名。 信頼できる証明機関は一意の実際の名前と ID を使用して証明書のサブジェクト名フィールドを設定するため、これは理論的にはアプリ開発者ごとに一意です。

このコンストラクトは、"5 部構成のタプル" と呼ばれることもあります。

注意

署名されていないパッケージにも (1) 公開元が必要です。(2) 公開元には未署名マーカー (OID.2.25.311729368913984317654407730594956997722=1) が含まれている必要があります。(3) 未署名マーカーは公開元文字列の最後のフィールドである必要があり、(4) 署名されていないパッケージには証明書または署名はありません。

パッケージ ID フィールドの制限

フィールド データ型 制限 説明
名前 パッケージ文字列 最小: 3
最大: 50
Validate 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
Validate API あたりの使用可能な値 (パッケージ文字列に関するセクションを参照)
Publisher String 最小:1
最大: 8192
X.509 あたりの使用可能な値
PublisherId String 最小: 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 など) を使用して比較する必要があります。

パッケージ ID の nameresourceid フィールドはパッケージ文字列です。

PackageId オブジェクト

PackageId は、5 部構成のタプルを個々のフィールド (NameVersionArchitectureResourceIdPublisher) として含むオブジェクトです。

パッケージの完全名

パッケージの完全名は、パッケージ ID の 5 つの部分 (名前、バージョン、アーキテクチャ、ResourceId、公開元) のすべてから派生した不透明な文字列です。

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

たとえば、Windows フォト アプリの 1 つのパッケージの完全名は "Microsoft.Windows.Photos_2020.20090.1002.0_x64__8wekyb3d8bbwe" です。ここで、"Microsoft.Windows.Photos" は名前、"2020.20090.1002.0" はバージョン番号、"x64" はターゲット プロセッサ アーキテクチャ、リソース ID は空 (最後の 2 つのアンダースコアの間に内容がない)、"8wekyb3d8bbwe" は Microsoft の公開元 ID です。

パッケージの完全名によって、MSIX パッケージまたはバンドルが一意に識別されます。 2 つのパッケージまたはバンドルの内容が異なるが、パッケージの完全名が同じである場合はエラーです。

注意

MSIX は、前の用語 APPX の新しい名前です。 詳細については、「MSIX の概要」を参照してください。

パッケージ ファミリ名

パッケージ ファミリ名は、パッケージ ID の 2 つだけの部分 ("名前" と "公開元") から派生した不透明な文字列です。

<Name>_<PublisherId>

たとえば、Windows フォト アプリのパッケージ ファミリ名は "Microsoft.Windows.Photos_8wekyb3d8bbwe" です。"Microsoft.Windows.Photos" は名前、"8wekyb3d8bbwe" は Microsoft の公開元 ID です。

パッケージ ファミリ名は、多くの場合、"バージョンレスのパッケージの完全名" と呼ばれます。

注意

パッケージ ファミリ名にはアーキテクチャとリソース ID もないため、これは厳密には正しくありません。

注意

通常、データとセキュリティのスコープはパッケージ ファミリです。 たとえば、バージョン 1.0.0.0 のメモ帳パッケージからインストールしたメモ帳アプリでワードラップを有効にするように構成した場合、エクスペリエンスが低下します。 その後、メモ帳が 1.0.0.1 に更新されると、構成データは新しいバージョンのパッケージに引き継がれません。

公開元 ID

パッケージ ファミリ名は、次の形式の文字列です。

<name>_<publisherid>

公開元 ID には、いくつか非常に特殊なプロパティがあります。

  • 公開元から派生
  • MinLength = MaxLength = 13 文字 [固定サイズ]
  • 使用可能な文字 (正規表現として) = a-hj-km-np-tv-z0-9
    • Base-32、Crockford バリアント (つまり、I (アイ)、L (エル)、O (オー) または U (ユー) 以外の英数字 (A-Z0-9))
  • 順次比較で大文字と小文字を区別しない --- ABCDEFABCDEFG == abcdefabcdefg

よって、公開元 ID に % : \ / " ? などの 文字は表示されません。

詳細については、PackageFamilyNameFromId および PackageNameAndPublisherIdFromFamilyName に関する記事を参照してください。

公開元 ID は、多くの場合、PublisherId と呼ばれます。

公開元 ID の存在理由

公開元 ID が存在するのは、公開元が証明書の X.509 名/署名者と一致する必要があるためです。したがって、次のようになります。

  • 非常に大きくなる場合があります (長さ <= 8192 文字)
  • 扱いにくい文字や制限された文字 (円記号など) が含まれる場合があります。

これらの問題により、一部の X.509 文字列はファイルシステム、レジストリ、URL、およびその他のコンテキストで使用できなくなる可能性があります。

PublisherId を作成するにはどうすればよいですか?

PackageNameAndPublisherIdFromFamilyName を使用して、PackageFamilyName から PublisherId を抽出します。

PackageIdFromFullName を使用して PackageFullName から PublisherId を抽出します。

Publisher から PublisherId を作成する必要があるケースはまれですが、利用可能な 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 を結果の形式 xyz_<publisherid> のパッケージ ファミリ名に変換することで、PublisherId が作成されます。 このレシピは安定しており、信頼性が高いものです。

SDK から appmodel.h を使用してコンパイルし、kernel32.lib (または kernelbase.lib、onecore.lib、API セットを使用している場合は api-ms-win-appmodel-runtime-l1.lib) とリンクするだけで済みます。

パッケージ ID のプロセッサ アーキテクチャについて

よくある誤解として、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 はそのうちの 1 つを指す <Application Executable=...> を宣言することしかできません)。 必要なビットのみをインストールできるバンドルがあることを考えると、これは極めて一般的でない方法といえます。 不適切というわけではなく、ただ高度で変わった方法です。

また、Architecture=x86 (または x64|arm|arm64) は、パッケージに指定のアーキテクチャの実行可能コードのみが含まれているという意味ではありません。 これは、圧倒的に一般的なケースにすぎません。

注意

このコンテキストで "コード" または "実行可能コード" に言及する場合は、移植可能な実行可能 (PE) ファイルを指しています。

パッケージ ID では大文字と小文字が区別されますか?

ほとんどの場合区別されませんが、Publisher では大文字と小文字が区別されます。

ほかのフィールド (NameResourceIdPublisherIdPackageFullNamePackageFamilyName) では区別されません。 これらのフィールドでは大文字と小文字が保持されますが、大文字と小文字は区別されずに比較されます。

参照

パッケージ ID

PackageFamilyNameFromId

PackageNameAndPublisherIdFromFamilyName