Guide pratique pour créer un package d’application (C++)
Découvrez comment créer un package d’application pour une application Windows à l’aide de l’API d’empaquetage.
Si vous souhaitez créer manuellement un package d’application de bureau, vous pouvez également utiliser l’outil MakeAppx.exe qui utilise l’API d’empaquetage. Pour plus d’informations, consultez Packager d’applications (MakeAppx.exe).
Si vous utilisez Visual Studio, il est recommandé d’utiliser l’Assistant Création de package Visual Studio pour empaqueter votre application. Pour plus d’informations, consultez Empaqueter une application UWP à l’aide de Visual Studio.
Instructions
Étape 1 : Créer un enregistreur de package
Pour créer un enregistreur de package, appelez la méthode IAppxFactory::CreatePackageWriter . Le premier paramètre est un flux de sortie dans lequel le package sera écrit. Le deuxième paramètre est un pointeur vers une structure APPX_PACKAGE_SETTINGS qui spécifie les paramètres du package. Le troisième paramètre est un paramètre de sortie qui reçoit un pointeur vers un pointeur IAppxPackageWriter .
#include <windows.h>
#include <shlwapi.h>
#include <AppxPackaging.h>
// We store the produced package under this file name.
const LPCWSTR OutputPackagePath = L"HelloWorld.appx";
int wmain()
{
HRESULT hr = S_OK;
// Specify the appropriate COM threading model
hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
if (SUCCEEDED(hr))
{
// Create a package writer
IAppxPackageWriter* packageWriter = NULL;
hr = GetPackageWriter(OutputPackagePath, &packageWriter);
}
}
//
// Creates an app package writer with default settings.
//
// Parameters:
// outputFileName
// Fully qualified name of the app package (.appx file) to be created.
// writer
// On success, receives the created instance of IAppxPackageWriter.
//
HRESULT GetPackageWriter(
_In_ LPCWSTR outputFileName,
_Outptr_ IAppxPackageWriter** writer)
{
const LPCWSTR Sha256AlgorithmUri = L"https://www.w3.org/2001/04/xmlenc#sha256";
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 for the package
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;
}
Étape 2 : Ajouter les fichiers de charge utile de votre application au package
Appelez la méthode IAppxPackageWriter::AddPayloadFile pour ajouter des fichiers au package. Le premier paramètre est le chemin d’accès relatif du fichier. Le deuxième paramètre indique le type de contenu du fichier. Le troisième paramètre spécifie les options de l’énumération APPX_COMPRESSION_OPTION . Le quatrième paramètre est le flux d’entrée du fichier.
// Path where all input files are stored
const LPCWSTR DataPath = L"Data\\";
// Add all payload files to the package writer
for (int i = 0; SUCCEEDED(hr) && (i < PayloadFilesCount); i++)
{
IStream* fileStream = NULL;
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;
}
}
}
Le code précédent utilise ces définitions de variables et GetFileStream
la fonction d’assistance.
#include <strsafe.h>
#include <shlwapi.h>
// The produced app 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,
};
//
// Creates a readable IStream over the specified file. For simplicity, we assume that the fully
// qualified file name is 100 characters or less. Your code should
// handle longer names, and allocate the buffer dynamically.
//
// Parameters:
// path
// Path of the folder that contains the file to be opened; must end with a '\'
// fileName
// Name, of the file to be opened, not including the path
// stream
// On success, receives the created instance of IStream
//
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, // don't create new file
NULL, // no template
stream);
}
return hr;
}
Étape 3 : Ajouter le manifeste du package au package
Chaque package doit avoir un manifeste de package. Pour ajouter le manifeste du package au package, créez un flux d’entrée pour le fichier, puis appelez la méthode IAppxPackageWriter::Close pour écrire le manifeste à la fin du package et fermer le flux de sortie pour l’enregistreur de package.
Ce code utilise la GetFileStream
fonction d’assistance indiquée à l’étape précédente pour créer le flux pour le manifeste du package.
// We read the app package's manifest from this file
const LPCWSTR ManifestFileName = L"AppxManifest.xml";
IStream* manifestStream = NULL;
hr = GetFileStream(DataPath, ManifestFileName, &manifestStream);
if (SUCCEEDED(hr))
{
hr = packageWriter->Close(manifestStream);
}
if (manifestStream != NULL)
{
manifestStream->Release();
manifestStream = NULL;
}
Étape 4 : Nettoyer l’enregistreur de package
Avant de revenir à partir de la wmain
fonction, appelez la méthode Release pour propre l’enregistreur de package et appelez la fonction CoUninitialize.
if (packageWriter != NULL)
{
packageWriter->Release();
packageWriter = NULL;
}
CoUninitialize();
Rubriques connexes
-
Exemples
-
Référence