-
Notifications
You must be signed in to change notification settings - Fork 3.2k
/
CreateBundle.cpp
209 lines (181 loc) · 6.19 KB
/
CreateBundle.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
// 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 APIs to produce
// an Appx Bundle from a list of app packages and resource packages on disk.
//
// For simplicity, the list of packages to be bundled is hard coded in this
// sample. A fully functional application might get its input from other
// sources.
#include <stdio.h>
#include <windows.h>
#include <strsafe.h>
#include <shlwapi.h>
#include <AppxPackaging.h> // For Appx Bundle APIs
#include "CreateBundle.h"
// Path where all input files are stored
const LPCWSTR DataPath = L"Data\\";
// The produced bundle's content consists of these files taken from the data folder
const int PayloadPackagesCount = 2;
const LPCWSTR PayloadPackagesName[PayloadPackagesCount] = {
L"MainAppPackage.appx",
L"ResourcePackage.lang-de.appx"
};
// The produced package will be stored under this file name
const LPCWSTR OutputBundlePath = L"sample.appxbundle";
//
// 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 Bundle writer with default settings, given the
// output file name.
//
// Parameters:
// outputFileName - Name including path to the bundle (.appxbundle file) to
// be created.
// writer - Output parameter pointing to the created instance of
// IAppxBundleWriter when this function succeeds.
//
HRESULT GetBundleWriter(
_In_ LPCWSTR outputFileName,
_Outptr_ IAppxBundleWriter** writer)
{
HRESULT hr = S_OK;
IStream* outputStream = NULL;
IAppxBundleFactory* appxBundleFactory = NULL;
// Create a stream over the output file where the bundle 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 a new Appx Bundle factory
if (SUCCEEDED(hr))
{
hr = CoCreateInstance(
__uuidof(AppxBundleFactory),
NULL,
CLSCTX_INPROC_SERVER,
__uuidof(IAppxBundleFactory),
(LPVOID*)(&appxBundleFactory));
}
// Create a new bundle writer using the factory
if (SUCCEEDED(hr))
{
hr = appxBundleFactory->CreateBundleWriter(
outputStream,
0, // by specifying 0, the bundle will have an automatically
// generated version number based on the current time
writer);
}
// Clean up allocated resources
if (appxBundleFactory != NULL)
{
appxBundleFactory->Release();
appxBundleFactory = 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"CreateBundle sample\n\n");
HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
if (SUCCEEDED(hr))
{
// Create a bundle writer object
IAppxBundleWriter* bundleWriter = NULL;
wprintf(L"\nCreating bundle writer\n\n");
hr = GetBundleWriter(OutputBundlePath, &bundleWriter);
// Add all payload packages to the package writer
for (int i = 0; SUCCEEDED(hr) && (i < PayloadPackagesCount); i++)
{
IStream* payloadPackageStream = NULL;
wprintf(L"Adding payload package: %s\n", PayloadPackagesName[i]);
hr = GetFileStream(DataPath, PayloadPackagesName[i], &payloadPackageStream);
if (SUCCEEDED(hr))
{
bundleWriter->AddPayloadPackage(
PayloadPackagesName[i],
payloadPackageStream);
}
if (payloadPackageStream != NULL)
{
payloadPackageStream->Release();
payloadPackageStream = NULL;
}
}
// Close the bundle writer to flush the output stream
if (SUCCEEDED(hr))
{
hr = bundleWriter->Close();
}
// Clean up allocated resources
if (bundleWriter != NULL)
{
bundleWriter->Release();
bundleWriter = NULL;
}
CoUninitialize();
}
if (SUCCEEDED(hr))
{
wprintf(L"\nBundle successfully saved to %s.\n", OutputBundlePath);
}
else
{
wprintf(L"\nBundle creation failed with HRESULT 0x%08X.\n", hr);
}
return SUCCEEDED(hr) ? 0 : 1;
}