Cómo crear un paquete de aplicación (C++)
Obtenga información sobre cómo crear un paquete de aplicación para una aplicación de Windows mediante la API de empaquetado.
Si desea crear manualmente un paquete de aplicación de escritorio, también puede usar la herramienta MakeAppx.exe que utiliza la API de empaquetado. Consulte App packager (MakeAppx.exe) para obtener más información.
Si usa Visual Studio, se recomienda usar el Asistente para empaquetado de Visual Studio para empaquetar la aplicación. Para obtener más información, consulta Empaquetar una aplicación para UWP con Visual Studio.
Instrucciones
Paso 1: Crear un escritor de paquetes
Para crear un escritor de paquetes, llame al método IAppxFactory::CreatePackageWriter . El primer parámetro es un flujo de salida donde se escribirá el paquete. El segundo parámetro es un puntero a una estructura de APPX_PACKAGE_SETTINGS que especifica la configuración del paquete. El tercer parámetro es un parámetro de salida que recibe un puntero a un puntero 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;
}
Paso 2: Agregar los archivos de carga de la aplicación al paquete
Llame al método IAppxPackageWriter::AddPayloadFile para agregar archivos al paquete. El primer parámetro es la ruta de acceso relativa del archivo. El segundo parámetro indica el tipo de contenido del archivo. El tercer parámetro especifica las opciones de la enumeración APPX_COMPRESSION_OPTION . El cuarto parámetro es el flujo de entrada del archivo.
// 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;
}
}
}
El código anterior usa estas definiciones de variables y GetFileStream
la función auxiliar.
#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;
}
Paso 3: Agregar el manifiesto del paquete al paquete
Cada paquete debe tener un manifiesto de paquete. Para agregar el manifiesto del paquete al paquete, cree un flujo de entrada para el archivo y, a continuación, llame al método IAppxPackageWriter::Close para escribir el manifiesto al final del paquete y cierre el flujo de salida para el escritor de paquetes.
Este código usa la GetFileStream
función auxiliar que se muestra en el paso anterior para crear la secuencia para el manifiesto del paquete.
// 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;
}
Paso 4: Limpiar el escritor de paquetes
Antes de volver de la wmain
función, llame al método Release para limpiar el escritor de paquetes y llamar a la función CoUninitialize .
if (packageWriter != NULL)
{
packageWriter->Release();
packageWriter = NULL;
}
CoUninitialize();
Temas relacionados
-
Muestras
-
Referencia