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

267 lines
7.7 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 packaging APIs to produce
// an Appx package from a list of files on disk.
//
// For the sake of simplicity, the list of files to be packaged is hard coded
// in this sample. A fully functional application might read its list of
// files from user input, or even generate content dynamically.
#include <stdio.h>
#include <windows.h>
#include <strsafe.h>
#include <shlwapi.h>
#include <AppxPackaging.h> // For Appx Packaging APIs
#include "CreateAppx.h"
// Path where all input files are stored
const LPCWSTR DataPath = L"Data\\";
// The produced Appx package's content consists of these files, with
// corresponding content types and compression options.
const int PayloadFilesCount = 4;
const LPCWSTR PayloadFilesName[PayloadFilesCount] = {
L"AppTile.png",
L"Default.html",
L"images\\smiley.jpg",
L"Error.html",
};
const LPCWSTR PayloadFilesContentType[PayloadFilesCount] = {
L"image/png",
L"text/html",
L"image/jpeg",
L"text/html",
};
const APPX_COMPRESSION_OPTION PayloadFilesCompression[PayloadFilesCount] = {
APPX_COMPRESSION_OPTION_NONE,
APPX_COMPRESSION_OPTION_NORMAL,
APPX_COMPRESSION_OPTION_NONE,
APPX_COMPRESSION_OPTION_NORMAL,
};
// The Appx package's manifest is read from this file
const LPCWSTR ManifestFileName = L"AppxManifest.xml";
// The hash algorithm to be used for the package's block map is SHA2-256
const LPCWSTR Sha256AlgorithmUri = L"http://www.w3.org/2001/04/xmlenc#sha256";
// The produced package will be stored under this file name
const LPCWSTR OutputPackagePath = L"HelloWorld.appx";
//
// Function to create a readable IStream over the file whose name is the
// concatenation of the path and fileName parameters. For simplicity, file
// names including path are assumed to be 100 characters or less. A real
// application should be able to handle longer names and allocate the
// necessary buffer dynamically.
//
// Parameters:
// path - Path of the folder containing the file to be opened, ending with a
// slash ('\') character
// fileName - Name, not including path, of the file to be opened
// stream - Output parameter pointing to the created instance of IStream over
// the specified file when this function succeeds.
//
HRESULT GetFileStream(
_In_ LPCWSTR path,
_In_ LPCWSTR fileName,
_Outptr_ IStream** stream)
{
HRESULT hr = S_OK;
const int MaxFileNameLength = 100;
WCHAR fullFileName[MaxFileNameLength + 1];
// Create full file name by concatenating path and fileName
hr = StringCchCopyW(fullFileName, MaxFileNameLength, path);
if (SUCCEEDED(hr))
{
hr = StringCchCat(fullFileName, MaxFileNameLength, fileName);
}
// Create stream for reading the file
if (SUCCEEDED(hr))
{
hr = SHCreateStreamOnFileEx(
fullFileName,
STGM_READ | STGM_SHARE_EXCLUSIVE,
0, // default file attributes
FALSE, // do not create new file
NULL, // no template
stream);
}
return hr;
}
//
// Function to create an Appx package writer with default settings, given the
// output file name.
//
// Parameters:
// outputFileName - Name including path to the Appx package (.appx file) to be
// created.
// writer - Output parameter pointing to the created instance of
// IAppxPackageWriter when this function succeeds.
//
HRESULT GetPackageWriter(
_In_ LPCWSTR outputFileName,
_Outptr_ IAppxPackageWriter** writer)
{
HRESULT hr = S_OK;
IStream* outputStream = NULL;
IUri* hashMethod = NULL;
APPX_PACKAGE_SETTINGS packageSettings = {0};
IAppxFactory* appxFactory = NULL;
// Create a stream over the output file where the package will be written
hr = SHCreateStreamOnFileEx(
outputFileName,
STGM_CREATE | STGM_WRITE | STGM_SHARE_EXCLUSIVE,
0, // default file attributes
TRUE, // create file if it does not exist
NULL, // no template
&outputStream);
// Create default package writer settings, including hash algorithm URI
// and Zip format.
if (SUCCEEDED(hr))
{
hr = CreateUri(
Sha256AlgorithmUri,
Uri_CREATE_CANONICALIZE,
0, // reserved parameter
&hashMethod);
}
if (SUCCEEDED(hr))
{
packageSettings.forceZip32 = TRUE;
packageSettings.hashMethod = hashMethod;
}
// Create a new Appx factory
if (SUCCEEDED(hr))
{
hr = CoCreateInstance(
__uuidof(AppxFactory),
NULL,
CLSCTX_INPROC_SERVER,
__uuidof(IAppxFactory),
(LPVOID*)(&appxFactory));
}
// Create a new package writer using the factory
if (SUCCEEDED(hr))
{
hr = appxFactory->CreatePackageWriter(
outputStream,
&packageSettings,
writer);
}
// Clean up allocated resources
if (appxFactory != NULL)
{
appxFactory->Release();
appxFactory = NULL;
}
if (hashMethod != NULL)
{
hashMethod->Release();
hashMethod = NULL;
}
if (outputStream != NULL)
{
outputStream->Release();
outputStream = NULL;
}
return hr;
}
//
// Main entry point of the sample
//
int wmain()
{
wprintf(L"Copyright (c) Microsoft Corporation. All rights reserved.\n");
wprintf(L"CreateAppx sample\n\n");
HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
if (SUCCEEDED(hr))
{
// Create a package writer
IAppxPackageWriter* packageWriter = NULL;
IStream* manifestStream = NULL;
wprintf(L"\nCreating package writer\n\n");
hr = GetPackageWriter(OutputPackagePath, &packageWriter);
// Add all payload files to the package writer
for (int i = 0; SUCCEEDED(hr) && (i < PayloadFilesCount); i++)
{
IStream* fileStream = NULL;
wprintf(L"Adding file: %s\n", PayloadFilesName[i]);
hr = GetFileStream(DataPath, PayloadFilesName[i], &fileStream);
if (SUCCEEDED(hr))
{
packageWriter->AddPayloadFile(
PayloadFilesName[i],
PayloadFilesContentType[i],
PayloadFilesCompression[i],
fileStream);
}
if (fileStream != NULL)
{
fileStream->Release();
fileStream = NULL;
}
}
// Add manifest to package and close package writer
if (SUCCEEDED(hr))
{
wprintf(L"\nClosing package writer and adding AppxManifest.xml as the package manifest\n");
hr = GetFileStream(DataPath, ManifestFileName, &manifestStream);
}
if (SUCCEEDED(hr))
{
hr = packageWriter->Close(manifestStream);
}
// Clean up allocated resources
if (manifestStream != NULL)
{
manifestStream->Release();
manifestStream = NULL;
}
if (packageWriter != NULL)
{
packageWriter->Release();
packageWriter = NULL;
}
CoUninitialize();
}
if (SUCCEEDED(hr))
{
wprintf(L"\nPackage successfully saved to %s.\n", OutputPackagePath);
}
else
{
wprintf(L"\nPackage creation failed with HRESULT 0x%08X.\n", hr);
}
return SUCCEEDED(hr) ? 0 : 1;
}