2025-11-28 00:35:46 +09:00

322 lines
8.6 KiB
C++

// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// Copyright (c) Microsoft Corporation. All rights reserved
// This is a simple application which uses the Appx Bundle Manifest APIs
// to read metadata from an Appx Bundle on disk.
#include <stdio.h>
#include <windows.h>
#include <strsafe.h>
#include <shlwapi.h>
#include <AppxPackaging.h> // For Appx Bundle APIs
#include "DescribeBundle.h"
//
// Function to read a subset of attributes from the identity of either a bundle
// or a payload package in the bundle.
//
// Parameters:
// identity - Instance of IAppxManifestPackageId obtained from the bundle manifest
// using either the IAppxBundleManifestReader::GetPackageId or the
// IAppxBundleManifestPackageInfo::GetPackageId method.
//
HRESULT ReadManifestIdentity(
_In_ IAppxManifestPackageId* identity)
{
HRESULT hr = S_OK;
LPWSTR packageFullName = NULL;
LPWSTR packageName = NULL;
UINT64 packageVersion = 0;
hr = identity->GetPackageFullName(&packageFullName);
if (SUCCEEDED(hr))
{
hr = identity->GetName(&packageName);
}
if (SUCCEEDED(hr))
{
hr = identity->GetVersion(&packageVersion);
}
if (SUCCEEDED(hr))
{
wprintf(L"Full name: %s\n", packageFullName);
wprintf(L"Name: %s\n", packageName);
wprintf(L"Version: ");
// Convert version number from 64-bit integer to dot-quad form
for (int bitPosition = 0x30; bitPosition >= 0; bitPosition -= 0x10)
{
UINT64 versionWord = (packageVersion >> bitPosition) & 0xFFFF;
wprintf(L"%llu.", versionWord);
}
wprintf(L"\n");
}
// Free all string buffers returned from the manifest API
CoTaskMemFree(packageFullName);
CoTaskMemFree(packageName);
return hr;
}
//
// Function to read a subset of attributes from the bundle manifest's
// <Packages> element.
//
// Parameters:
// packages - Instance of IAppxBundleManifestPackageInfoEnumerator obtained
// from a bundle manifest using the
// IAppxBundleManifestReader::GetPackageInfoItems method.
//
HRESULT ReadManifestPackages(
_In_ IAppxBundleManifestPackageInfoEnumerator* packages)
{
HRESULT hr = S_OK;
BOOL hasCurrent = FALSE;
UINT32 packagesCount = 0;
hr = packages->GetHasCurrent(&hasCurrent);
while (SUCCEEDED(hr) && hasCurrent)
{
IAppxBundleManifestPackageInfo* packageInfo = NULL;
LPWSTR packageFileName = NULL;
APPX_BUNDLE_PAYLOAD_PACKAGE_TYPE packageType = APPX_BUNDLE_PAYLOAD_PACKAGE_TYPE_APPLICATION;
IAppxManifestPackageId* packageIdentity = NULL;
hr = packages->GetCurrent(&packageInfo);
if (SUCCEEDED(hr))
{
hr = packageInfo->GetFileName(&packageFileName);
}
if (SUCCEEDED(hr))
{
packagesCount++;
wprintf(L"Package #%u: %s\n", packagesCount, packageFileName);
}
// Read the payload package's type
if (SUCCEEDED(hr))
{
hr = packageInfo->GetPackageType(&packageType);
}
if (SUCCEEDED(hr))
{
if (packageType == APPX_BUNDLE_PAYLOAD_PACKAGE_TYPE_APPLICATION)
{
wprintf(L"This is an app package.\n");
}
else if (packageType == APPX_BUNDLE_PAYLOAD_PACKAGE_TYPE_RESOURCE)
{
wprintf(L"This is a resource package.\n");
}
}
// Read the payload package's identity
if (SUCCEEDED(hr))
{
hr = packageInfo->GetPackageId(&packageIdentity);
}
if (SUCCEEDED(hr))
{
hr = ReadManifestIdentity(packageIdentity);
}
wprintf(L"\n");
if (SUCCEEDED(hr))
{
hr = packages->MoveNext(&hasCurrent);
}
if (packageInfo != NULL)
{
packageInfo->Release();
packageInfo = NULL;
}
if (packageIdentity != NULL)
{
packageIdentity->Release();
packageIdentity = NULL;
}
CoTaskMemFree(packageFileName);
}
wprintf(L"The bundle contains %u package(s)\n", packagesCount);
return hr;
}
//
// Function to print a subset of information from a bundle manifest reader.
// Many methods in the bundle manifest API have similar usage patterns.
// Only a representative subset of API methods are shown here.
//
// Parameters:
// manifestReader - Instance of IAppxBundleManifestReader created from a
// bundle manifest.
//
HRESULT ReadManifest(
_In_ IAppxBundleManifestReader* manifestReader)
{
HRESULT hr = S_OK;
IAppxManifestPackageId* bundleId = NULL;
IAppxBundleManifestPackageInfoEnumerator* packages = NULL;
wprintf(L"\nReading <Identity> element\n");
hr = manifestReader->GetPackageId(&bundleId);
if (SUCCEEDED(hr))
{
hr = ReadManifestIdentity(bundleId);
}
wprintf(L"\nReading <Packages> element\n");
if (SUCCEEDED(hr))
{
hr = manifestReader->GetPackageInfoItems(&packages);
}
if (SUCCEEDED(hr))
{
hr = ReadManifestPackages(packages);
}
// Clean up allocated resources
if (bundleId != NULL)
{
bundleId->Release();
bundleId = NULL;
}
if (packages != NULL)
{
packages->Release();
packages = NULL;
}
return hr;
}
//
// Function to create an Appx Bundle reader given the input file name.
//
// Parameters:
// inputFileName - Path to the Appx Bundle (.appxbundle file) to be opened.
// reader - Output parameter pointing to the created instance of
// IAppxBundleReader when this function succeeds.
//
HRESULT GetBundleReader(
_In_ LPCWSTR inputFileName,
_Outptr_ IAppxBundleReader** reader)
{
HRESULT hr = S_OK;
IAppxBundleFactory* appxBundleFactory = NULL;
IStream* inputStream = NULL;
// Create a new Appx bundle factory
hr = CoCreateInstance(
__uuidof(AppxBundleFactory),
NULL,
CLSCTX_INPROC_SERVER,
__uuidof(IAppxBundleFactory),
(LPVOID*)(&appxBundleFactory));
// Create a stream over the input bundle file
if (SUCCEEDED(hr))
{
hr = SHCreateStreamOnFileEx(
inputFileName,
STGM_READ | STGM_SHARE_EXCLUSIVE,
0, // default file attributes
FALSE, // do not create new file
NULL, // no template
&inputStream);
}
// Create a new bundle reader using the factory
if (SUCCEEDED(hr))
{
hr = appxBundleFactory->CreateBundleReader(
inputStream,
reader);
}
// Clean up allocated resources
if (inputStream != NULL)
{
inputStream->Release();
inputStream = NULL;
}
if (appxBundleFactory != NULL)
{
appxBundleFactory->Release();
appxBundleFactory = NULL;
}
return hr;
}
//
// Main entry point of the sample
//
int wmain(
_In_ int argc,
_In_reads_(argc) wchar_t** argv)
{
wprintf(L"Copyright (c) Microsoft Corporation. All rights reserved.\n");
wprintf(L"DescribeBundle sample\n\n");
if (argc != 2)
{
wprintf(L"Usage: DescribeBundle.exe inputFile\n");
wprintf(L" inputFile: Path to the Appx Bundle to read\n");
return 2;
}
HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
if (SUCCEEDED(hr))
{
// Create a bundle reader using the file name given in command line
IAppxBundleReader* bundleReader = NULL;
IAppxBundleManifestReader* manifestReader = NULL;
hr = GetBundleReader(argv[1], &bundleReader);
wprintf(L"\nReading the bundle manifest\n");
// Get manifest reader for the bundle and read from the manifest
if (SUCCEEDED(hr))
{
hr = bundleReader->GetManifest(&manifestReader);
}
if (SUCCEEDED(hr))
{
hr = ReadManifest(manifestReader);
}
// Clean up allocated resources
if (manifestReader != NULL)
{
manifestReader->Release();
manifestReader = NULL;
}
if (bundleReader != NULL)
{
bundleReader->Release();
bundleReader = NULL;
}
CoUninitialize();
}
if (SUCCEEDED(hr))
{
wprintf(L"\nBundle metadata read successfully.\n");
}
else
{
wprintf(L"\nFailed to read bundle metadata with HRESULT 0x%08X.\n", hr);
}
return SUCCEEDED(hr) ? 0 : 1;
}