@joebigelow / wix-1 / commits / 0354a00e

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);