Add support for BundleExtensions.
Sean Hall committed
Mar 29, 2020 at 19:14 UTC
0354a00e74492ad8d930c5bf499bc8606e48b1c9
15 files changed
+701
-14
src/engine/EngineForApplication.cpp
+1
-1
@@ -593,7 +593,7 @@ static HRESULT BAEngineSetVariableString(
593
if (wzVariable && *wzVariable)
594
{
595
hr = VariableSetString(&pContext->pEngineState->variables, wzVariable, wzValue, FALSE);
596
- ExitOnFailure(hr, "Failed to set numeric variable.");
596
+ ExitOnFailure(hr, "Failed to set string variable.");
597
}
598
else
599
{
src/engine/EngineForApplication.h
+2
-2
@@ -24,11 +24,11 @@ enum WM_BURN
24
25
// structs
26
27
-struct BOOTSTRAPPER_ENGINE_CONTEXT
27
+typedef struct _BOOTSTRAPPER_ENGINE_CONTEXT
28
{
29
BURN_ENGINE_STATE* pEngineState;
30
DWORD dwThreadId;
31
-};
31
+} BOOTSTRAPPER_ENGINE_CONTEXT;
32
33
// function declarations
34
src/engine/EngineForExtension.cpp
new
+405
@@ -0,0 +1,405 @@
1
+// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
+
3
+#include "precomp.h"
4
+
5
+static HRESULT BEEngineEscapeString(
6
+ __in BURN_EXTENSION_ENGINE_CONTEXT* /*pContext*/,
7
+ __in BUNDLE_EXTENSION_ENGINE_ESCAPESTRING_ARGS* pArgs,
8
+ __in BUNDLE_EXTENSION_ENGINE_ESCAPESTRING_RESULTS* pResults
9
+ )
10
+{
11
+ HRESULT hr = S_OK;
12
+ LPWSTR sczValue = NULL;
13
+ size_t cchRemaining = 0;
14
+ LPCWSTR wzIn = pArgs->wzIn;
15
+ LPWSTR wzOut = pResults->wzOut;
16
+ DWORD* pcchOut = &pResults->cchOut;
17
+
18
+ if (wzIn && *wzIn)
19
+ {
20
+ hr = VariableEscapeString(wzIn, &sczValue);
21
+ if (SUCCEEDED(hr))
22
+ {
23
+ if (wzOut)
24
+ {
25
+ hr = ::StringCchCopyExW(wzOut, *pcchOut, sczValue, NULL, &cchRemaining, STRSAFE_FILL_BEHIND_NULL);
26
+ if (STRSAFE_E_INSUFFICIENT_BUFFER == hr)
27
+ {
28
+ hr = E_MOREDATA;
29
+ ::StringCchLengthW(sczValue, STRSAFE_MAX_CCH, &cchRemaining);
30
+ *pcchOut = cchRemaining;
31
+ }
32
+ }
33
+ else
34
+ {
35
+ ::StringCchLengthW(sczValue, STRSAFE_MAX_CCH, &cchRemaining);
36
+ *pcchOut = cchRemaining;
37
+ }
38
+ }
39
+ }
40
+ else
41
+ {
42
+ hr = E_INVALIDARG;
43
+ }
44
+
45
+ StrSecureZeroFreeString(sczValue);
46
+ return hr;
47
+}
48
+
49
+static HRESULT BEEngineEvaluateCondition(
50
+ __in BURN_EXTENSION_ENGINE_CONTEXT* pContext,
51
+ __in BUNDLE_EXTENSION_ENGINE_EVALUATECONDITION_ARGS* pArgs,
52
+ __in BUNDLE_EXTENSION_ENGINE_EVALUATECONDITION_RESULTS* pResults
53
+ )
54
+{
55
+ HRESULT hr = S_OK;
56
+ LPCWSTR wzCondition = pArgs->wzCondition;
57
+ BOOL* pf = &pResults->f;
58
+
59
+ if (wzCondition && *wzCondition)
60
+ {
61
+ hr = ConditionEvaluate(&pContext->pEngineState->variables, wzCondition, pf);
62
+ }
63
+ else
64
+ {
65
+ hr = E_INVALIDARG;
66
+ }
67
+
68
+ return hr;
69
+}
70
+
71
+static HRESULT BEEngineFormatString(
72
+ __in BURN_EXTENSION_ENGINE_CONTEXT* pContext,
73
+ __in BUNDLE_EXTENSION_ENGINE_FORMATSTRING_ARGS* pArgs,
74
+ __in BUNDLE_EXTENSION_ENGINE_FORMATSTRING_RESULTS* pResults
75
+ )
76
+{
77
+ HRESULT hr = S_OK;
78
+ LPWSTR sczValue = NULL;
79
+ DWORD cchValue = 0;
80
+ LPCWSTR wzIn = pArgs->wzIn;
81
+ LPWSTR wzOut = pResults->wzOut;
82
+ DWORD* pcchOut = &pResults->cchOut;
83
+
84
+ if (wzIn && *wzIn)
85
+ {
86
+ hr = VariableFormatString(&pContext->pEngineState->variables, wzIn, &sczValue, &cchValue);
87
+ if (SUCCEEDED(hr))
88
+ {
89
+ if (wzOut)
90
+ {
91
+ hr = ::StringCchCopyExW(wzOut, *pcchOut, sczValue, NULL, NULL, STRSAFE_FILL_BEHIND_NULL);
92
+ if (FAILED(hr))
93
+ {
94
+ *pcchOut = cchValue;
95
+ if (STRSAFE_E_INSUFFICIENT_BUFFER == hr)
96
+ {
97
+ hr = E_MOREDATA;
98
+ }
99
+ }
100
+ }
101
+ else
102
+ {
103
+ hr = E_MOREDATA;
104
+ *pcchOut = cchValue;
105
+ }
106
+ }
107
+ }
108
+ else
109
+ {
110
+ hr = E_INVALIDARG;
111
+ }
112
+
113
+ StrSecureZeroFreeString(sczValue);
114
+ return hr;
115
+}
116
+
117
+static HRESULT BEEngineGetVariableNumeric(
118
+ __in BURN_EXTENSION_ENGINE_CONTEXT* pContext,
119
+ __in BUNDLE_EXTENSION_ENGINE_GETVARIABLENUMERIC_ARGS* pArgs,
120
+ __in BUNDLE_EXTENSION_ENGINE_GETVARIABLENUMERIC_RESULTS* pResults
121
+ )
122
+{
123
+ HRESULT hr = S_OK;
124
+ LPCWSTR wzVariable = pArgs->wzVariable;
125
+ LONGLONG* pllValue = &pResults->llValue;
126
+
127
+ if (wzVariable && *wzVariable)
128
+ {
129
+ hr = VariableGetNumeric(&pContext->pEngineState->variables, wzVariable, pllValue);
130
+ }
131
+ else
132
+ {
133
+ hr = E_INVALIDARG;
134
+ }
135
+
136
+ return hr;
137
+}
138
+
139
+static HRESULT BEEngineGetVariableString(
140
+ __in BURN_EXTENSION_ENGINE_CONTEXT* pContext,
141
+ __in BUNDLE_EXTENSION_ENGINE_GETVARIABLESTRING_ARGS* pArgs,
142
+ __in BUNDLE_EXTENSION_ENGINE_GETVARIABLESTRING_RESULTS* pResults
143
+ )
144
+{
145
+ HRESULT hr = S_OK;
146
+ LPWSTR sczValue = NULL;
147
+ size_t cchRemaining = 0;
148
+ LPCWSTR wzVariable = pArgs->wzVariable;
149
+ LPWSTR wzValue = pResults->wzValue;
150
+ DWORD* pcchValue = &pResults->cchValue;
151
+
152
+ if (wzVariable && *wzVariable)
153
+ {
154
+ hr = VariableGetString(&pContext->pEngineState->variables, wzVariable, &sczValue);
155
+ if (SUCCEEDED(hr))
156
+ {
157
+ if (wzValue)
158
+ {
159
+ hr = ::StringCchCopyExW(wzValue, *pcchValue, sczValue, NULL, &cchRemaining, STRSAFE_FILL_BEHIND_NULL);
160
+ if (STRSAFE_E_INSUFFICIENT_BUFFER == hr)
161
+ {
162
+ hr = E_MOREDATA;
163
+
164
+ ::StringCchLengthW(sczValue, STRSAFE_MAX_CCH, &cchRemaining);
165
+ *pcchValue = cchRemaining + 1;
166
+ }
167
+ }
168
+ else
169
+ {
170
+ hr = E_MOREDATA;
171
+
172
+ ::StringCchLengthW(sczValue, STRSAFE_MAX_CCH, &cchRemaining);
173
+ *pcchValue = cchRemaining + 1;
174
+ }
175
+ }
176
+ }
177
+ else
178
+ {
179
+ hr = E_INVALIDARG;
180
+ }
181
+
182
+ StrSecureZeroFreeString(sczValue);
183
+ return hr;
184
+}
185
+
186
+static HRESULT BEEngineGetVariableVersion(
187
+ __in BURN_EXTENSION_ENGINE_CONTEXT* pContext,
188
+ __in BUNDLE_EXTENSION_ENGINE_GETVARIABLEVERSION_ARGS* pArgs,
189
+ __in BUNDLE_EXTENSION_ENGINE_GETVARIABLEVERSION_RESULTS* pResults
190
+ )
191
+{
192
+ HRESULT hr = S_OK;
193
+ LPCWSTR wzVariable = pArgs->wzVariable;
194
+ DWORD64* pqwValue = &pResults->qwValue;
195
+
196
+ if (wzVariable && *wzVariable)
197
+ {
198
+ hr = VariableGetVersion(&pContext->pEngineState->variables, wzVariable, pqwValue);
199
+ }
200
+ else
201
+ {
202
+ hr = E_INVALIDARG;
203
+ }
204
+
205
+ return hr;
206
+}
207
+
208
+static HRESULT BEEngineLog(
209
+ __in BURN_EXTENSION_ENGINE_CONTEXT* /*pContext*/,
210
+ __in BUNDLE_EXTENSION_ENGINE_LOG_ARGS* pArgs,
211
+ __in BUNDLE_EXTENSION_ENGINE_LOG_RESULTS* /*pResults*/
212
+ )
213
+{
214
+ HRESULT hr = S_OK;
215
+ REPORT_LEVEL rl = REPORT_NONE;
216
+ BUNDLE_EXTENSION_LOG_LEVEL level = pArgs->level;
217
+ LPCWSTR wzMessage = pArgs->wzMessage;
218
+
219
+ switch (level)
220
+ {
221
+ case BUNDLE_EXTENSION_LOG_LEVEL_STANDARD:
222
+ rl = REPORT_STANDARD;
223
+ break;
224
+
225
+ case BUNDLE_EXTENSION_LOG_LEVEL_VERBOSE:
226
+ rl = REPORT_VERBOSE;
227
+ break;
228
+
229
+ case BUNDLE_EXTENSION_LOG_LEVEL_DEBUG:
230
+ rl = REPORT_DEBUG;
231
+ break;
232
+
233
+ case BUNDLE_EXTENSION_LOG_LEVEL_ERROR:
234
+ rl = REPORT_ERROR;
235
+ break;
236
+
237
+ default:
238
+ ExitFunction1(hr = E_INVALIDARG);
239
+ }
240
+
241
+ hr = LogStringLine(rl, "%ls", wzMessage);
242
+ ExitOnFailure(hr, "Failed to log Bundle Extension message.");
243
+
244
+LExit:
245
+ return hr;
246
+}
247
+
248
+static HRESULT BEEngineSetVariableLiteralString(
249
+ __in BURN_EXTENSION_ENGINE_CONTEXT* pContext,
250
+ __in const BUNDLE_EXTENSION_ENGINE_SETVARIABLELITERALSTRING_ARGS* pArgs,
251
+ __in BUNDLE_EXTENSION_ENGINE_SETVARIABLELITERALSTRING_RESULTS* /*pResults*/
252
+ )
253
+{
254
+ HRESULT hr = S_OK;
255
+ LPCWSTR wzVariable = pArgs->wzVariable;
256
+ LPCWSTR wzValue = pArgs->wzValue;
257
+
258
+ if (wzVariable && *wzVariable)
259
+ {
260
+ hr = VariableSetLiteralString(&pContext->pEngineState->variables, wzVariable, wzValue, FALSE);
261
+ ExitOnFailure(hr, "Failed to set literal string variable.");
262
+ }
263
+ else
264
+ {
265
+ hr = E_INVALIDARG;
266
+ ExitOnFailure(hr, "Bundle Extension did not provide variable name.");
267
+ }
268
+
269
+LExit:
270
+ return hr;
271
+}
272
+
273
+static HRESULT BEEngineSetVariableNumeric(
274
+ __in BURN_EXTENSION_ENGINE_CONTEXT* pContext,
275
+ __in const BUNDLE_EXTENSION_ENGINE_SETVARIABLENUMERIC_ARGS* pArgs,
276
+ __in BUNDLE_EXTENSION_ENGINE_SETVARIABLENUMERIC_RESULTS* /*pResults*/
277
+ )
278
+{
279
+ HRESULT hr = S_OK;
280
+ LPCWSTR wzVariable = pArgs->wzVariable;
281
+ LONGLONG llValue = pArgs->llValue;
282
+
283
+ if (wzVariable && *wzVariable)
284
+ {
285
+ hr = VariableSetNumeric(&pContext->pEngineState->variables, wzVariable, llValue, FALSE);
286
+ ExitOnFailure(hr, "Failed to set numeric variable.");
287
+ }
288
+ else
289
+ {
290
+ hr = E_INVALIDARG;
291
+ ExitOnFailure(hr, "Bundle Extension did not provide variable name.");
292
+ }
293
+
294
+LExit:
295
+ return hr;
296
+}
297
+
298
+static HRESULT BEEngineSetVariableString(
299
+ __in BURN_EXTENSION_ENGINE_CONTEXT* pContext,
300
+ __in const BUNDLE_EXTENSION_ENGINE_SETVARIABLESTRING_ARGS* pArgs,
301
+ __in BUNDLE_EXTENSION_ENGINE_SETVARIABLESTRING_RESULTS* /*pResults*/
302
+ )
303
+{
304
+ HRESULT hr = S_OK;
305
+ LPCWSTR wzVariable = pArgs->wzVariable;
306
+ LPCWSTR wzValue = pArgs->wzValue;
307
+
308
+ if (wzVariable && *wzVariable)
309
+ {
310
+ hr = VariableSetString(&pContext->pEngineState->variables, wzVariable, wzValue, FALSE);
311
+ ExitOnFailure(hr, "Failed to set string variable.");
312
+ }
313
+ else
314
+ {
315
+ hr = E_INVALIDARG;
316
+ ExitOnFailure(hr, "Bundle Extension did not provide variable name.");
317
+ }
318
+
319
+LExit:
320
+ return hr;
321
+}
322
+
323
+static HRESULT BEEngineSetVariableVersion(
324
+ __in BURN_EXTENSION_ENGINE_CONTEXT* pContext,
325
+ __in const BUNDLE_EXTENSION_ENGINE_SETVARIABLEVERSION_ARGS* pArgs,
326
+ __in BUNDLE_EXTENSION_ENGINE_SETVARIABLEVERSION_RESULTS* /*pResults*/
327
+ )
328
+{
329
+ HRESULT hr = S_OK;
330
+ LPCWSTR wzVariable = pArgs->wzVariable;
331
+ DWORD64 qwValue = pArgs->qwValue;
332
+
333
+ if (wzVariable && *wzVariable)
334
+ {
335
+ hr = VariableSetVersion(&pContext->pEngineState->variables, wzVariable, qwValue, FALSE);
336
+ ExitOnFailure(hr, "Failed to set version variable.");
337
+ }
338
+ else
339
+ {
340
+ hr = E_INVALIDARG;
341
+ ExitOnFailure(hr, "Bundle Extension did not provide variable name.");
342
+ }
343
+
344
+LExit:
345
+ return hr;
346
+}
347
+
348
+HRESULT WINAPI EngineForExtensionProc(
349
+ __in BUNDLE_EXTENSION_ENGINE_MESSAGE message,
350
+ __in const LPVOID pvArgs,
351
+ __inout LPVOID pvResults,
352
+ __in_opt LPVOID pvContext
353
+ )
354
+{
355
+ HRESULT hr = S_OK;
356
+ BURN_EXTENSION_ENGINE_CONTEXT* pContext = reinterpret_cast<BURN_EXTENSION_ENGINE_CONTEXT*>(pvContext);
357
+
358
+ if (!pContext || !pvArgs || !pvResults)
359
+ {
360
+ ExitFunction1(hr = E_INVALIDARG);
361
+ }
362
+
363
+ switch (message)
364
+ {
365
+ case BUNDLE_EXTENSION_ENGINE_MESSAGE_ESCAPESTRING:
366
+ hr = BEEngineEscapeString(pContext, reinterpret_cast<BUNDLE_EXTENSION_ENGINE_ESCAPESTRING_ARGS*>(pvArgs), reinterpret_cast<BUNDLE_EXTENSION_ENGINE_ESCAPESTRING_RESULTS*>(pvResults));
367
+ break;
368
+ case BUNDLE_EXTENSION_ENGINE_MESSAGE_EVALUATECONDITION:
369
+ hr = BEEngineEvaluateCondition(pContext, reinterpret_cast<BUNDLE_EXTENSION_ENGINE_EVALUATECONDITION_ARGS*>(pvArgs), reinterpret_cast<BUNDLE_EXTENSION_ENGINE_EVALUATECONDITION_RESULTS*>(pvResults));
370
+ break;
371
+ case BUNDLE_EXTENSION_ENGINE_MESSAGE_FORMATSTRING:
372
+ hr = BEEngineFormatString(pContext, reinterpret_cast<BUNDLE_EXTENSION_ENGINE_FORMATSTRING_ARGS*>(pvArgs), reinterpret_cast<BUNDLE_EXTENSION_ENGINE_FORMATSTRING_RESULTS*>(pvResults));
373
+ break;
374
+ case BUNDLE_EXTENSION_ENGINE_MESSAGE_GETVARIABLENUMERIC:
375
+ hr = BEEngineGetVariableNumeric(pContext, reinterpret_cast<BUNDLE_EXTENSION_ENGINE_GETVARIABLENUMERIC_ARGS*>(pvArgs), reinterpret_cast<BUNDLE_EXTENSION_ENGINE_GETVARIABLENUMERIC_RESULTS*>(pvResults));
376
+ break;
377
+ case BUNDLE_EXTENSION_ENGINE_MESSAGE_GETVARIABLESTRING:
378
+ hr = BEEngineGetVariableString(pContext, reinterpret_cast<BUNDLE_EXTENSION_ENGINE_GETVARIABLESTRING_ARGS*>(pvArgs), reinterpret_cast<BUNDLE_EXTENSION_ENGINE_GETVARIABLESTRING_RESULTS*>(pvResults));
379
+ break;
380
+ case BUNDLE_EXTENSION_ENGINE_MESSAGE_GETVARIABLEVERSION:
381
+ hr = BEEngineGetVariableVersion(pContext, reinterpret_cast<BUNDLE_EXTENSION_ENGINE_GETVARIABLEVERSION_ARGS*>(pvArgs), reinterpret_cast<BUNDLE_EXTENSION_ENGINE_GETVARIABLEVERSION_RESULTS*>(pvResults));
382
+ break;
383
+ case BUNDLE_EXTENSION_ENGINE_MESSAGE_LOG:
384
+ hr = BEEngineLog(pContext, reinterpret_cast<BUNDLE_EXTENSION_ENGINE_LOG_ARGS*>(pvArgs), reinterpret_cast<BUNDLE_EXTENSION_ENGINE_LOG_RESULTS*>(pvResults));
385
+ break;
386
+ case BUNDLE_EXTENSION_ENGINE_MESSAGE_SETVARIABLELITERALSTRING:
387
+ hr = BEEngineSetVariableLiteralString(pContext, reinterpret_cast<BUNDLE_EXTENSION_ENGINE_SETVARIABLELITERALSTRING_ARGS*>(pvArgs), reinterpret_cast<BUNDLE_EXTENSION_ENGINE_SETVARIABLELITERALSTRING_RESULTS*>(pvResults));
388
+ break;
389
+ case BUNDLE_EXTENSION_ENGINE_MESSAGE_SETVARIABLENUMERIC:
390
+ hr = BEEngineSetVariableNumeric(pContext, reinterpret_cast<BUNDLE_EXTENSION_ENGINE_SETVARIABLENUMERIC_ARGS*>(pvArgs), reinterpret_cast<BUNDLE_EXTENSION_ENGINE_SETVARIABLENUMERIC_RESULTS*>(pvResults));
391
+ break;
392
+ case BUNDLE_EXTENSION_ENGINE_MESSAGE_SETVARIABLESTRING:
393
+ hr = BEEngineSetVariableString(pContext, reinterpret_cast<BUNDLE_EXTENSION_ENGINE_SETVARIABLESTRING_ARGS*>(pvArgs), reinterpret_cast<BUNDLE_EXTENSION_ENGINE_SETVARIABLESTRING_RESULTS*>(pvResults));
394
+ break;
395
+ case BUNDLE_EXTENSION_ENGINE_MESSAGE_SETVARIABLEVERSION:
396
+ hr = BEEngineSetVariableVersion(pContext, reinterpret_cast<BUNDLE_EXTENSION_ENGINE_SETVARIABLEVERSION_ARGS*>(pvArgs), reinterpret_cast<BUNDLE_EXTENSION_ENGINE_SETVARIABLEVERSION_RESULTS*>(pvResults));
397
+ break;
398
+ default:
399
+ hr = E_NOTIMPL;
400
+ break;
401
+ }
402
+
403
+LExit:
404
+ return hr;
405
+}
src/engine/EngineForExtension.h
new
+27
@@ -0,0 +1,27 @@
1
+#pragma once
2
+// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
3
+
4
+
5
+#if defined(__cplusplus)
6
+extern "C" {
7
+#endif
8
+
9
+// structs
10
+
11
+typedef struct _BURN_EXTENSION_ENGINE_CONTEXT
12
+{
13
+ BURN_ENGINE_STATE* pEngineState;
14
+} BURN_EXTENSION_ENGINE_CONTEXT;
15
+
16
+// function declarations
17
+
18
+HRESULT WINAPI EngineForExtensionProc(
19
+ __in BUNDLE_EXTENSION_ENGINE_MESSAGE message,
20
+ __in const LPVOID pvArgs,
21
+ __inout LPVOID pvResults,
22
+ __in_opt LPVOID pvContext
23
+ );
24
+
25
+#if defined(__cplusplus)
26
+}
27
+#endif
src/engine/burnextension.cpp
new
+184
@@ -0,0 +1,184 @@
1
+// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
+
3
+#include "precomp.h"
4
+
5
+// function definitions
6
+
7
+/*******************************************************************
8
+ BurnExtensionParseFromXml -
9
+
10
+*******************************************************************/
11
+EXTERN_C HRESULT BurnExtensionParseFromXml(
12
+ __in BURN_EXTENSIONS* pBurnExtensions,
13
+ __in BURN_PAYLOADS* pBaPayloads,
14
+ __in IXMLDOMNode* pixnBundle
15
+ )
16
+{
17
+ HRESULT hr = S_OK;
18
+ IXMLDOMNodeList* pixnNodes = NULL;
19
+ IXMLDOMNode* pixnNode = NULL;
20
+ DWORD cNodes = 0;
21
+
22
+ // Select BundleExtension nodes.
23
+ hr = XmlSelectNodes(pixnBundle, L"BundleExtension", &pixnNodes);
24
+ ExitOnFailure(hr, "Failed to select BundleExtension nodes.");
25
+
26
+ // Get BundleExtension node count.
27
+ hr = pixnNodes->get_length((long*)&cNodes);
28
+ ExitOnFailure(hr, "Failed to get BundleExtension node count.");
29
+
30
+ if (!cNodes)
31
+ {
32
+ ExitFunction();
33
+ }
34
+
35
+ // Allocate memory for BundleExtensions.
36
+ pBurnExtensions->rgExtensions = (BURN_EXTENSION*)MemAlloc(sizeof(BURN_EXTENSION) * cNodes, TRUE);
37
+ ExitOnNull(pBurnExtensions->rgExtensions, hr, E_OUTOFMEMORY, "Failed to allocate memory for BundleExtension structs.");
38
+
39
+ pBurnExtensions->cExtensions = cNodes;
40
+
41
+ // parse search elements
42
+ for (DWORD i = 0; i < cNodes; ++i)
43
+ {
44
+ BURN_EXTENSION* pExtension = &pBurnExtensions->rgExtensions[i];
45
+
46
+ hr = XmlNextElement(pixnNodes, &pixnNode, NULL);
47
+ ExitOnFailure(hr, "Failed to get next node.");
48
+
49
+ // @Id
50
+ hr = XmlGetAttributeEx(pixnNode, L"Id", &pExtension->sczId);
51
+ ExitOnFailure(hr, "Failed to get @Id.");
52
+
53
+ // @EntryPayloadId
54
+ hr = XmlGetAttributeEx(pixnNode, L"EntryPayloadId", &pExtension->sczEntryPayloadId);
55
+ ExitOnFailure(hr, "Failed to get @EntryPayloadId.");
56
+
57
+ hr = PayloadFindById(pBaPayloads, pExtension->sczEntryPayloadId, &pExtension->pEntryPayload);
58
+ ExitOnFailure(hr, "Failed to find BundleExtension EntryPayload '%ls'.", pExtension->sczEntryPayloadId);
59
+
60
+ // prepare next iteration
61
+ ReleaseNullObject(pixnNode);
62
+ }
63
+
64
+ hr = S_OK;
65
+
66
+LExit:
67
+ ReleaseObject(pixnNode);
68
+ ReleaseObject(pixnNodes);
69
+
70
+ return hr;
71
+}
72
+
73
+/*******************************************************************
74
+ BurnExtensionUninitialize -
75
+
76
+*******************************************************************/
77
+EXTERN_C void BurnExtensionUninitialize(
78
+ __in BURN_EXTENSIONS* pBurnExtensions
79
+ )
80
+{
81
+ if (pBurnExtensions->rgExtensions)
82
+ {
83
+ for (DWORD i = 0; i < pBurnExtensions->cExtensions; ++i)
84
+ {
85
+ BURN_EXTENSION* pExtension = &pBurnExtensions->rgExtensions[i];
86
+
87
+ ReleaseStr(pExtension->sczEntryPayloadId);
88
+ ReleaseStr(pExtension->sczId);
89
+ }
90
+ MemFree(pBurnExtensions->rgExtensions);
91
+ }
92
+
93
+ // clear struct
94
+ memset(pBurnExtensions, 0, sizeof(BURN_EXTENSIONS));
95
+}
96
+
97
+/*******************************************************************
98
+ BurnExtensionLoad -
99
+
100
+*******************************************************************/
101
+EXTERN_C HRESULT BurnExtensionLoad(
102
+ __in BURN_EXTENSIONS * pBurnExtensions,
103
+ __in BURN_EXTENSION_ENGINE_CONTEXT* pEngineContext
104
+ )
105
+{
106
+ HRESULT hr = S_OK;
107
+ BUNDLE_EXTENSION_CREATE_ARGS args = { };
108
+ BUNDLE_EXTENSION_CREATE_RESULTS results = { };
109
+
110
+ if (!pBurnExtensions->rgExtensions || !pBurnExtensions->cExtensions)
111
+ {
112
+ ExitFunction();
113
+ }
114
+
115
+ for (DWORD i = 0; i < pBurnExtensions->cExtensions; ++i)
116
+ {
117
+ BURN_EXTENSION* pExtension = &pBurnExtensions->rgExtensions[i];
118
+
119
+ memset(&args, 0, sizeof(BUNDLE_EXTENSION_CREATE_ARGS));
120
+ memset(&results, 0, sizeof(BUNDLE_EXTENSION_CREATE_RESULTS));
121
+
122
+ args.cbSize = sizeof(BUNDLE_EXTENSION_CREATE_ARGS);
123
+ args.pfnBundleExtensionEngineProc = EngineForExtensionProc;
124
+ args.pvBundleExtensionEngineProcContext = pEngineContext;
125
+ args.qwEngineAPIVersion = MAKEQWORDVERSION(0, 0, 0, 1); // TODO: need to decide whether to keep this, and if so when to update it.
126
+
127
+ results.cbSize = sizeof(BUNDLE_EXTENSION_CREATE_RESULTS);
128
+
129
+ // Load BundleExtension DLL.
130
+ pExtension->hBextModule = ::LoadLibraryExW(pExtension->pEntryPayload->sczLocalFilePath, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
131
+ ExitOnNullWithLastError(pExtension->hBextModule, hr, "Failed to load BundleExtension DLL '%ls': '%ls'.", pExtension->sczId, pExtension->pEntryPayload->sczLocalFilePath);
132
+
133
+ // Get BundleExtensionCreate entry-point.
134
+ PFN_BUNDLE_EXTENSION_CREATE pfnCreate = (PFN_BUNDLE_EXTENSION_CREATE)::GetProcAddress(pExtension->hBextModule, "BundleExtensionCreate");
135
+ ExitOnNullWithLastError(pfnCreate, hr, "Failed to get BundleExtensionCreate entry-point '%ls'.", pExtension->sczId);
136
+
137
+ // Create BundleExtension.
138
+ hr = pfnCreate(&args, &results);
139
+ ExitOnFailure(hr, "Failed to create BundleExtension '%ls'.", pExtension->sczId);
140
+
141
+ pExtension->pfnBurnExtensionProc = results.pfnBundleExtensionProc;
142
+ pExtension->pvBurnExtensionProcContext = results.pvBundleExtensionProcContext;
143
+ }
144
+
145
+LExit:
146
+ return hr;
147
+}
148
+
149
+/*******************************************************************
150
+ BurnExtensionUnload -
151
+
152
+*******************************************************************/
153
+EXTERN_C void BurnExtensionUnload(
154
+ __in BURN_EXTENSIONS * pBurnExtensions
155
+ )
156
+{
157
+ HRESULT hr = S_OK;
158
+
159
+ if (pBurnExtensions->rgExtensions)
160
+ {
161
+ for (DWORD i = 0; i < pBurnExtensions->cExtensions; ++i)
162
+ {
163
+ BURN_EXTENSION* pExtension = &pBurnExtensions->rgExtensions[i];
164
+
165
+ if (pExtension->hBextModule)
166
+ {
167
+ // Get BundleExtensionDestroy entry-point and call it if it exists.
168
+ PFN_BUNDLE_EXTENSION_DESTROY pfnDestroy = (PFN_BUNDLE_EXTENSION_DESTROY)::GetProcAddress(pExtension->hBextModule, "BundleExtensionDestroy");
169
+ if (pfnDestroy)
170
+ {
171
+ pfnDestroy();
172
+ }
173
+
174
+ // Free BundleExtension DLL.
175
+ if (!::FreeLibrary(pExtension->hBextModule))
176
+ {
177
+ hr = HRESULT_FROM_WIN32(::GetLastError());
178
+ TraceError(hr, "Failed to unload BundleExtension DLL.");
179
+ }
180
+ pExtension->hBextModule = NULL;
181
+ }
182
+ }
183
+ }
184
+}
src/engine/burnextension.h
new
+51
@@ -0,0 +1,51 @@
1
+#pragma once
2
+// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
3
+
4
+#define BEEAPI HRESULT __stdcall
5
+
6
+#if defined(__cplusplus)
7
+extern "C" {
8
+#endif
9
+
10
+// structs
11
+
12
+typedef struct _BURN_EXTENSION_ENGINE_CONTEXT BURN_EXTENSION_ENGINE_CONTEXT;
13
+
14
+typedef struct _BURN_EXTENSION
15
+{
16
+ LPWSTR sczEntryPayloadId;
17
+ LPWSTR sczId;
18
+
19
+ BURN_PAYLOAD* pEntryPayload;
20
+
21
+ HMODULE hBextModule;
22
+ PFN_BUNDLE_EXTENSION_PROC pfnBurnExtensionProc;
23
+ LPVOID pvBurnExtensionProcContext;
24
+} BURN_EXTENSION;
25
+
26
+typedef struct _BURN_EXTENSIONS
27
+{
28
+ BURN_EXTENSION* rgExtensions;
29
+ DWORD cExtensions;
30
+} BURN_EXTENSIONS;
31
+
32
+// functions
33
+
34
+HRESULT BurnExtensionParseFromXml(
35
+ __in BURN_EXTENSIONS* pBurnExtensions,
36
+ __in BURN_PAYLOADS* pBaPayloads,
37
+ __in IXMLDOMNode* pixnBundle
38
+ );
39
+void BurnExtensionUninitialize(
40
+ __in BURN_EXTENSIONS* pBurnExtensions
41
+ );
42
+HRESULT BurnExtensionLoad(
43
+ __in BURN_EXTENSIONS* pBurnExtensions,
44
+ __in BURN_EXTENSION_ENGINE_CONTEXT* pEngineContext
45
+ );
46
+void BurnExtensionUnload(
47
+ __in BURN_EXTENSIONS* pBurnExtensions
48
+ );
49
+#if defined(__cplusplus)
50
+}
51
+#endif
src/engine/core.h
+1
@@ -103,6 +103,7 @@ typedef struct _BURN_ENGINE_STATE
103
BURN_PACKAGES packages;
104
BURN_UPDATE update;
105
BURN_APPROVED_EXES approvedExes;
106
+ BURN_EXTENSIONS extensions;
107
108
HWND hMessageWindow;
109
HANDLE hMessageWindowThread;
src/engine/engine.cpp
+12
@@ -352,6 +352,8 @@ static void UninitializeEngineState(
352
353
ReleaseHandle(pEngineState->hMessageWindowThread);
354
355
+ BurnExtensionUninitialize(&pEngineState->extensions);
356
+
357
::DeleteCriticalSection(&pEngineState->userExperience.csEngineActive);
358
UserExperienceUninitialize(&pEngineState->userExperience);
359
@@ -493,6 +495,7 @@ static HRESULT RunNormal(
495
HANDLE hPipesCreatedEvent = NULL;
496
BOOL fContinueExecution = TRUE;
497
BOOL fReloadApp = FALSE;
498
+ BURN_EXTENSION_ENGINE_CONTEXT extensionEngineContext = { };
499
500
// Initialize logging.
501
hr = LoggingOpen(&pEngineState->log, &pEngineState->variables, pEngineState->command.display, pEngineState->registration.sczDisplayName);
@@ -537,6 +540,13 @@ static HRESULT RunNormal(
540
ExitOnFailure(hr, "Failed to set layout directory variable to value provided from command-line.");
541
}
542
543
+ // Setup the extension engine.
544
+ extensionEngineContext.pEngineState = pEngineState;
545
+
546
+ // Load the extensions.
547
+ hr = BurnExtensionLoad(&pEngineState->extensions, &extensionEngineContext);
548
+ ExitOnFailure(hr, "Failed to load BundleExtensions.");
549
+
550
do
551
{
552
fReloadApp = FALSE;
@@ -546,6 +556,8 @@ static HRESULT RunNormal(
556
} while (fReloadApp);
557
558
LExit:
559
+ BurnExtensionUnload(&pEngineState->extensions);
560
+
561
// If the message window is still around, close it.
562
UiCloseMessageWindow(pEngineState);
563
src/engine/engine.vcxproj
+6
-7
@@ -2,7 +2,7 @@
2
<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
3
4
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
5
- <Import Project="..\..\packages\WixToolset.BootstrapperCore.Native.4.0.12\build\WixToolset.BootstrapperCore.Native.props" Condition="Exists('..\..\packages\WixToolset.BootstrapperCore.Native.4.0.12\build\WixToolset.BootstrapperCore.Native.props')" />
5
+ <Import Project="..\..\packages\WixToolset.BootstrapperCore.Native.4.0.13\build\WixToolset.BootstrapperCore.Native.props" Condition="Exists('..\..\packages\WixToolset.BootstrapperCore.Native.4.0.13\build\WixToolset.BootstrapperCore.Native.props')" />
6
<Import Project="..\..\packages\WixToolset.DUtil.4.0.18\build\WixToolset.DUtil.props" Condition="Exists('..\..\packages\WixToolset.DUtil.4.0.18\build\WixToolset.DUtil.props')" />
7
8
<ItemGroup Label="ProjectConfigurations">
@@ -50,10 +50,12 @@
50
<ClCompile Include="apply.cpp" />
51
<ClCompile Include="approvedexe.cpp" />
52
<ClCompile Include="bitsengine.cpp" />
53
+ <ClCompile Include="burnextension.cpp" />
54
<ClCompile Include="catalog.cpp" />
55
<ClCompile Include="detect.cpp" />
56
<ClCompile Include="embedded.cpp" />
57
<ClCompile Include="EngineForApplication.cpp" />
58
+ <ClCompile Include="EngineForExtension.cpp" />
59
<ClCompile Include="cabextract.cpp" />
60
<ClCompile Include="cache.cpp" />
61
<ClCompile Include="condition.cpp" />
@@ -90,15 +92,11 @@
92
<ClCompile Include="variant.cpp" />
93
</ItemGroup>
94
93
- <ItemGroup>
94
- <ClInclude Include="..\inc\BootstrapperApplication.h" />
95
- <ClInclude Include="..\inc\BootstrapperEngine.h" />
96
- </ItemGroup>
97
-
95
<ItemGroup>
96
<ClInclude Include="apply.h" />
97
<ClInclude Include="approvedexe.h" />
98
<ClInclude Include="bitsengine.h" />
99
+ <ClInclude Include="burnextension.h" />
100
<ClInclude Include="cabextract.h" />
101
<ClInclude Include="cache.h" />
102
<ClInclude Include="catalog.h" />
@@ -110,6 +108,7 @@
108
<ClInclude Include="elevation.h" />
109
<ClInclude Include="embedded.h" />
110
<ClInclude Include="EngineForApplication.h" />
111
+ <ClInclude Include="EngineForExtension.h" />
112
<ClInclude Include="exeengine.h" />
113
<ClInclude Include="inc\engine.h" />
114
<ClInclude Include="logging.h" />
@@ -167,7 +166,7 @@ rc.exe -fo "$(OutDir)engine.res" "$(IntDir)engine.messages.rc"</Command>
166
<PropertyGroup>
167
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
168
</PropertyGroup>
170
- <Error Condition="!Exists('..\..\packages\WixToolset.BootstrapperCore.Native.4.0.12\build\WixToolset.BootstrapperCore.Native.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\WixToolset.BootstrapperCore.Native.4.0.12\build\WixToolset.BootstrapperCore.Native.props'))" />
169
+ <Error Condition="!Exists('..\..\packages\WixToolset.BootstrapperCore.Native.4.0.13\build\WixToolset.BootstrapperCore.Native.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\WixToolset.BootstrapperCore.Native.4.0.13\build\WixToolset.BootstrapperCore.Native.props'))" />
170
<Error Condition="!Exists('..\..\packages\WixToolset.DUtil.4.0.18\build\WixToolset.DUtil.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\WixToolset.DUtil.4.0.18\build\WixToolset.DUtil.props'))" />
171
<Error Condition="!Exists('..\..\packages\Nerdbank.GitVersioning.2.1.65\build\Nerdbank.GitVersioning.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Nerdbank.GitVersioning.2.1.65\build\Nerdbank.GitVersioning.targets'))" />
172
</Target>
src/engine/manifest.cpp
+4
@@ -116,6 +116,10 @@ extern "C" HRESULT ManifestLoadXmlFromBuffer(
116
hr = ApprovedExesParseFromXml(&pEngineState->approvedExes, pixeBundle);
117
ExitOnFailure(hr, "Failed to parse approved exes.");
118
119
+ // parse extensions
120
+ hr = BurnExtensionParseFromXml(&pEngineState->extensions, &pEngineState->userExperience.payloads, pixeBundle);
121
+ ExitOnFailure(hr, "Failed to parse extensions.");
122
+
123
LExit:
124
ReleaseObject(pixnChain);
125
ReleaseObject(pixnLog);
src/engine/packages.config
+1
-1
@@ -1,6 +1,6 @@
1
<?xml version="1.0" encoding="utf-8"?>
2
<packages>
3
<package id="Nerdbank.GitVersioning" version="2.1.65" targetFramework="native" developmentDependency="true" />
4
- <package id="WixToolset.BootstrapperCore.Native" version="4.0.12" targetFramework="native" />
4
+ <package id="WixToolset.BootstrapperCore.Native" version="4.0.13" targetFramework="native" />
5
<package id="WixToolset.DUtil" version="4.0.18" targetFramework="native" />
6
</packages>
\ No newline at end of file
src/engine/precomp.h
+4
@@ -61,6 +61,8 @@
61
62
#include "BootstrapperEngine.h"
63
#include "BootstrapperApplication.h"
64
+#include "BundleExtensionEngine.h"
65
+#include "BundleExtension.h"
66
67
#include "platform.h"
68
#include "variant.h"
@@ -73,6 +75,7 @@
75
#include "catalog.h"
76
#include "payload.h"
77
#include "cabextract.h"
78
+#include "burnextension.h"
79
#include "userexperience.h"
80
#include "package.h"
81
#include "update.h"
@@ -100,4 +103,5 @@
103
#include "netfxchainer.h"
104
105
#include "EngineForApplication.h"
106
+#include "EngineForExtension.h"
107
#include "engine.messages.h"
src/engine/userexperience.cpp
+1
-1
@@ -103,7 +103,7 @@ extern "C" HRESULT UserExperienceLoad(
103
104
// Load BA DLL.
105
pUserExperience->hUXModule = ::LoadLibraryExW(pUserExperience->payloads.rgPayloads[0].sczLocalFilePath, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
106
- ExitOnNullWithLastError(pUserExperience->hUXModule, hr, "Failed to load UX DLL.");
106
+ ExitOnNullWithLastError(pUserExperience->hUXModule, hr, "Failed to load BA DLL.");
107
108
// Get BootstrapperApplicationCreate entry-point.
109
PFN_BOOTSTRAPPER_APPLICATION_CREATE pfnCreate = (PFN_BOOTSTRAPPER_APPLICATION_CREATE)::GetProcAddress(pUserExperience->hUXModule, "BootstrapperApplicationCreate");
src/engine/userexperience.h
+1
-1
@@ -15,7 +15,7 @@ const DWORD MB_RETRYTRYAGAIN = 0xF;
15
16
// structs
17
18
-struct BOOTSTRAPPER_ENGINE_CONTEXT;
18
+typedef struct _BOOTSTRAPPER_ENGINE_CONTEXT BOOTSTRAPPER_ENGINE_CONTEXT;
19
20
typedef struct _BURN_USER_EXPERIENCE
21
{
src/engine/variable.cpp
+1
-1
@@ -309,7 +309,7 @@ extern "C" HRESULT VariablesParseFromXml(
309
hr = pixnNodes->get_length((long*)&cNodes);
310
ExitOnFailure(hr, "Failed to get variable node count.");
311
312
- // parse package elements
312
+ // parse variable elements
313
for (DWORD i = 0; i < cNodes; ++i)
314
{
315
hr = XmlNextElement(pixnNodes, &pixnNode, NULL);