备注
如果您要创建UWP应用程序包,请参阅使用MakeAppx.exe工具创建应用程序包。
了解如何使用打包API为Windows应用商店应用创建应用包。
如果要手动创建桌面应用程序包,还可以使用使用打包API的MakeAppx.exe工具。有关详细信息,请参阅App packager(MakeAppx.exe)。
如果您使用的是Visual Studio,建议您使用Visual Studio打包向导打包您的应用程序。有关更多详细信息,请参阅打包UWP应用程序。
说明
第1步:创建包编写器
要创建包编写器,请调用IAppxFactory :: CreatePackageWriter方法。第一个参数是将写入包的输出流。第二个参数是指向APPX_PACKAGE_SETTINGS结构的指针,该结构指定包设置。第三个参数是一个输出参数,它接收指向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;
}
第2步:将应用程序的有效内容文件添加到包中
调用IAppxPackageWriter :: AddPayloadFile方法将文件添加到包中。第一个参数是文件的相对路径。第二个参数表示文件的内容类型。第三个参数指定APPX_COMPRESSION_OPTION枚举中的选项。第四个参数是文件的输入流。以下效果展示
黄铜浮球阀, 不锈钢法兰浮球阀, 不锈钢水箱浮球阀, Q941F-16P不锈钢电动球阀, 丝扣浮球阀, 黄铜小孔浮球阀, Z45X暗杆软密封闸阀, GLY储油罐量油孔, FZT防爆阻火呼吸人孔, CWX微型电动球阀, Q941F电动开关球阀, Q941F电动法兰球阀, Q911F电动内螺纹球阀, Q671F气动对夹式球阀, Q611N气动高压球阀, Q641F气动带手动球阀, Q611F气动三片式球阀, Q611F气动两片式球阀, Q641F气动调节球阀, Q971F电动对夹球阀, Q641F不锈钢气动球阀, 不锈钢高压球阀, 超高压球阀, Q41Y高压硬密封球阀, QJ41M耐高温球阀, QJ41M不锈钢高温球阀, 法兰高温球阀, Q41H高温硬密封球阀, Q41H金属硬密封高温球阀, (Q45F)T型三通球阀, (Q44F)L型三通球阀, KHB3K高压三通球阀, BQ71F薄型保温球阀, Q11F螺纹球阀, Q11F内螺纹球阀, Q21F外螺纹球阀, Q41F法兰球阀, Q41F法兰式球阀, Q61F焊接球阀, Q61F全焊接球阀, Q61F焊接式球阀, Q71F对夹球阀, Q71F对夹式球阀, Q61N对焊球阀, Q91F卡套球阀, Q91F不锈钢卡套球阀, Q41N锻钢球阀, Q61N焊接锻钢球阀, Q41N高压锻钢球阀, KQ41F不锈钢抗硫球阀, 切断球阀, 气动切断球阀-气动O型切断球阀, 电动切断球阀-电动O型切断球阀, Q46F不锈钢四通球阀, Q46F四通球阀, Q41F燃气球阀, Q41F燃气专用球阀, Q81F卫生球阀, Q81F快装球阀, Q81F卫生级快装球阀, Q81F卫生级球阀, Q681F卫生级气动球阀, 广式球阀, Q11F广式内螺纹球阀, Q21F广式外螺纹球阀, Q41F广式法兰球阀, Q11F丝口球阀, Q11F丝扣球阀, V型球阀, 电动V型球阀, 气动V型球阀, YJZQ高压液压球阀, KHBF-KHMF法兰式高压球阀, CJZQ高压球阀, VH3V二位三通高压球阀, BKH-MKH高压球阀, VH2V直通高压球阀, BME高压球阀, KHB高压球阀, KHP-PKH高压板式球阀, (喷煤粉)卸灰球阀, Q647MF气动卸灰球阀(喷煤粉专用球阀)
// 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;
}
}
}
前面的代码使用这些变量定义和GetFileStream
辅助函数。
#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;
}
第3步:将包清单添加到包中
每个包都必须有一个包清单。要将包清单添加到包中,请为该文件创建输入流,然后调用IAppxPackageWriter :: Close方法在包的末尾写入清单并关闭包编写器的输出流。
此代码使用GetFileStream
上一步中显示的帮助程序函数为程序包清单创建流。
// 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;
}
第4步:清理包编写器
在从wmain
函数返回之前,调用Release方法来清理包编写器并调用CoUninitialize函数。
if (packageWriter != NULL)
{
packageWriter->Release();
packageWriter = NULL;
}
CoUninitialize();