diff --git a/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj b/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj
index 337e04a701..82e6059dcc 100644
--- a/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj
+++ b/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj
@@ -817,6 +817,9 @@
true
+
+ true
+
true
@@ -832,6 +835,9 @@
true
+
+ true
+
true
diff --git a/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj.filters b/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj.filters
index 10e263ad17..6618fcdd05 100644
--- a/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj.filters
+++ b/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj.filters
@@ -852,6 +852,9 @@
TestData
+
+ TestData
+
TestData
@@ -867,6 +870,9 @@
TestData
+
+ TestData
+
TestData
diff --git a/src/AppInstallerCLITests/TestData/Installer-Good-WithStub.msixbundle b/src/AppInstallerCLITests/TestData/Installer-Good-WithStub.msixbundle
new file mode 100644
index 0000000000..40b5a01e53
Binary files /dev/null and b/src/AppInstallerCLITests/TestData/Installer-Good-WithStub.msixbundle differ
diff --git a/src/AppInstallerCLITests/TestData/Manifest-Good-MsixBundleInstaller-WithStub.yaml b/src/AppInstallerCLITests/TestData/Manifest-Good-MsixBundleInstaller-WithStub.yaml
new file mode 100644
index 0000000000..d8615bd146
--- /dev/null
+++ b/src/AppInstallerCLITests/TestData/Manifest-Good-MsixBundleInstaller-WithStub.yaml
@@ -0,0 +1,13 @@
+PackageIdentifier: AppInstallerCliTest.GoodMsixBundleInstaller
+PackageVersion: 43690.48059.52428.56797
+PackageLocale: es-MX
+PackageName: es-MX package name
+Publisher: es-MX publisher
+PackageFamilyName: FakeInstallerForTesting_125rzkzqaqjwj
+MinimumOSVersion: 10.0.16299.0
+InstallerType: msix
+Installers:
+ - Architecture: x64
+ InstallerUrl: Installer-Good-WithStub.msixbundle
+ManifestType: merged
+ManifestVersion: 1.0.0
diff --git a/src/AppInstallerCLITests/YamlManifest.cpp b/src/AppInstallerCLITests/YamlManifest.cpp
index ab25c53c3b..79f20771c7 100644
--- a/src/AppInstallerCLITests/YamlManifest.cpp
+++ b/src/AppInstallerCLITests/YamlManifest.cpp
@@ -1150,6 +1150,20 @@ TEST_CASE("ReadManifestAndValidateMsixBundleInstallers_Success", "[ManifestValid
REQUIRE(0 == errors.size());
}
+TEST_CASE("ReadManifestAndValidateMsixBundleInstallers_WithStub_Success", "[ManifestValidation]")
+{
+ TestDataFile testFile("Manifest-Good-MsixBundleInstaller-WithStub.yaml");
+ Manifest manifest = YamlParser::CreateFromPath(testFile);
+
+ // Update the installer path for testing
+ REQUIRE(1 == manifest.Installers.size());
+ TestDataFile msixFile(manifest.Installers[0].Url.c_str());
+ manifest.Installers[0].Url = msixFile.GetPath().u8string();
+
+ auto errors = ValidateManifestInstallers(manifest);
+ REQUIRE(0 == errors.size());
+}
+
TEST_CASE("ReadManifestAndValidateMsixBundleInstallers_InconsistentFields", "[ManifestValidation]")
{
TestDataFile testFile("Manifest-Bad-InconsistentMsixBundleInstallerFields.yaml");
diff --git a/src/AppInstallerCommonCore/MsixInfo.cpp b/src/AppInstallerCommonCore/MsixInfo.cpp
index 802b7bcf3a..6256bb8eea 100644
--- a/src/AppInstallerCommonCore/MsixInfo.cpp
+++ b/src/AppInstallerCommonCore/MsixInfo.cpp
@@ -623,7 +623,7 @@ namespace AppInstaller::Msix
return Utility::ConvertToUTF8(GetPackageFullNameWide());
}
- std::vector> MsixInfo::GetAppPackages() const
+ std::vector> MsixInfo::GetAppPackages(bool includeStub) const
{
if (!m_isBundle)
{
@@ -648,11 +648,19 @@ namespace AppInstaller::Msix
APPX_BUNDLE_PAYLOAD_PACKAGE_TYPE packageType;
THROW_IF_FAILED(packageInfo->GetPackageType(&packageType));
+ // Check flat bundle case.
UINT64 offset;
THROW_IF_FAILED(packageInfo->GetOffset(&offset));
- const bool isContained = offset != 0;
+ bool isContained = offset != 0;
- if (isContained && packageType == APPX_BUNDLE_PAYLOAD_PACKAGE_TYPE::APPX_BUNDLE_PAYLOAD_PACKAGE_TYPE_APPLICATION)
+ // Check stub package case.
+ ComPtr packageInfo4;
+ THROW_IF_FAILED(packageInfo.As(&packageInfo4));
+ BOOL isStub = FALSE;
+ THROW_IF_FAILED(packageInfo4->GetIsStub(&isStub));
+
+ if (isContained && (includeStub || !isStub) &&
+ packageType == APPX_BUNDLE_PAYLOAD_PACKAGE_TYPE::APPX_BUNDLE_PAYLOAD_PACKAGE_TYPE_APPLICATION)
{
wil::unique_cotaskmem_string fileName;
THROW_IF_FAILED(packageInfo->GetFileName(&fileName));
@@ -680,10 +688,10 @@ namespace AppInstaller::Msix
return packages;
}
- std::vector MsixInfo::GetAppPackageManifests() const
+ std::vector MsixInfo::GetAppPackageManifests(bool includeStub) const
{
std::vector manifests;
- auto packages = GetAppPackages();
+ auto packages = GetAppPackages(includeStub);
for (const auto& package : packages)
{
ComPtr manifestReader;
diff --git a/src/AppInstallerCommonCore/Public/AppInstallerMsixInfo.h b/src/AppInstallerCommonCore/Public/AppInstallerMsixInfo.h
index 5ea9dba4a9..8d52581b75 100644
--- a/src/AppInstallerCommonCore/Public/AppInstallerMsixInfo.h
+++ b/src/AppInstallerCommonCore/Public/AppInstallerMsixInfo.h
@@ -91,7 +91,7 @@ namespace AppInstaller::Msix
void WriteToFileHandle(std::string_view packageFile, HANDLE target, IProgressCallback& progress);
// Get application package manifests from msix and msixbundle.
- std::vector GetAppPackageManifests() const;
+ std::vector GetAppPackageManifests(bool includeStub = false) const;
private:
bool m_isBundle;
@@ -99,8 +99,8 @@ namespace AppInstaller::Msix
Microsoft::WRL::ComPtr m_bundleReader;
Microsoft::WRL::ComPtr m_packageReader;
- // Get application packages.
- std::vector> GetAppPackages() const;
+ // Get application packages. Ignore stub packages if any.
+ std::vector> GetAppPackages(bool includeStub = false) const;
};
struct GetCertContextResult