aboutsummaryrefslogtreecommitdiff
path: root/src/burn/engine/variable.cpp
diff options
context:
space:
mode:
authorRob Mensching <rob@firegiant.com>2021-04-22 17:06:54 -0700
committerRob Mensching <rob@firegiant.com>2021-04-29 16:36:06 -0700
commitaf10c45d7b3a44af0b461a557847fe03263dcc10 (patch)
tree6a5c1532304782c36ffe4200b38f3afb76789a43 /src/burn/engine/variable.cpp
parent9c2aed97299fb96aeee3f1471ce40225437aaecf (diff)
downloadwix-af10c45d7b3a44af0b461a557847fe03263dcc10.tar.gz
wix-af10c45d7b3a44af0b461a557847fe03263dcc10.tar.bz2
wix-af10c45d7b3a44af0b461a557847fe03263dcc10.zip
Move burn into burn
Diffstat (limited to 'src/burn/engine/variable.cpp')
-rw-r--r--src/burn/engine/variable.cpp2323
1 files changed, 2323 insertions, 0 deletions
diff --git a/src/burn/engine/variable.cpp b/src/burn/engine/variable.cpp
new file mode 100644
index 00000000..6f818ff3
--- /dev/null
+++ b/src/burn/engine/variable.cpp
@@ -0,0 +1,2323 @@
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
6// structs
7
8typedef const struct _BUILT_IN_VARIABLE_DECLARATION
9{
10 LPCWSTR wzVariable;
11 PFN_INITIALIZEVARIABLE pfnInitialize;
12 DWORD_PTR dwpInitializeData;
13 BOOL fPersist;
14 BOOL fOverridable;
15} BUILT_IN_VARIABLE_DECLARATION;
16
17
18// constants
19
20const DWORD GROW_VARIABLE_ARRAY = 3;
21
22enum OS_INFO_VARIABLE
23{
24 OS_INFO_VARIABLE_NONE,
25 OS_INFO_VARIABLE_VersionNT,
26 OS_INFO_VARIABLE_VersionNT64,
27 OS_INFO_VARIABLE_ServicePackLevel,
28 OS_INFO_VARIABLE_NTProductType,
29 OS_INFO_VARIABLE_NTSuiteBackOffice,
30 OS_INFO_VARIABLE_NTSuiteDataCenter,
31 OS_INFO_VARIABLE_NTSuiteEnterprise,
32 OS_INFO_VARIABLE_NTSuitePersonal,
33 OS_INFO_VARIABLE_NTSuiteSmallBusiness,
34 OS_INFO_VARIABLE_NTSuiteSmallBusinessRestricted,
35 OS_INFO_VARIABLE_NTSuiteWebServer,
36 OS_INFO_VARIABLE_CompatibilityMode,
37 OS_INFO_VARIABLE_TerminalServer,
38 OS_INFO_VARIABLE_ProcessorArchitecture,
39 OS_INFO_VARIABLE_WindowsBuildNumber,
40};
41
42enum SET_VARIABLE
43{
44 SET_VARIABLE_NOT_BUILTIN,
45 SET_VARIABLE_OVERRIDE_BUILTIN,
46 SET_VARIABLE_OVERRIDE_PERSISTED_BUILTINS,
47 SET_VARIABLE_ANY,
48};
49
50// internal function declarations
51
52static HRESULT FormatString(
53 __in BURN_VARIABLES* pVariables,
54 __in_z LPCWSTR wzIn,
55 __out_z_opt LPWSTR* psczOut,
56 __out_opt SIZE_T* pcchOut,
57 __in BOOL fObfuscateHiddenVariables,
58 __out BOOL* pfContainsHiddenVariable
59 );
60static HRESULT GetFormatted(
61 __in BURN_VARIABLES* pVariables,
62 __in_z LPCWSTR wzVariable,
63 __out_z LPWSTR* psczValue,
64 __out BOOL* pfContainsHiddenVariable
65 );
66static HRESULT AddBuiltInVariable(
67 __in BURN_VARIABLES* pVariables,
68 __in LPCWSTR wzVariable,
69 __in PFN_INITIALIZEVARIABLE pfnInitialize,
70 __in DWORD_PTR dwpInitializeData,
71 __in BOOL fPersist,
72 __in BOOL fOverridable
73 );
74static HRESULT GetVariable(
75 __in BURN_VARIABLES* pVariables,
76 __in_z LPCWSTR wzVariable,
77 __out BURN_VARIABLE** ppVariable
78 );
79static HRESULT FindVariableIndexByName(
80 __in BURN_VARIABLES* pVariables,
81 __in_z LPCWSTR wzVariable,
82 __out DWORD* piVariable
83 );
84static HRESULT InsertVariable(
85 __in BURN_VARIABLES* pVariables,
86 __in_z LPCWSTR wzVariable,
87 __in DWORD iPosition
88 );
89static HRESULT SetVariableValue(
90 __in BURN_VARIABLES* pVariables,
91 __in_z LPCWSTR wzVariable,
92 __in BURN_VARIANT* pVariant,
93 __in SET_VARIABLE setBuiltin,
94 __in BOOL fLog
95 );
96static HRESULT InitializeVariableVersionNT(
97 __in DWORD_PTR dwpData,
98 __inout BURN_VARIANT* pValue
99 );
100static HRESULT InitializeVariableOsInfo(
101 __in DWORD_PTR dwpData,
102 __inout BURN_VARIANT* pValue
103 );
104static HRESULT InitializeVariableSystemInfo(
105 __in DWORD_PTR dwpData,
106 __inout BURN_VARIANT* pValue
107 );
108static HRESULT InitializeVariableComputerName(
109 __in DWORD_PTR dwpData,
110 __inout BURN_VARIANT* pValue
111 );
112static HRESULT InitializeVariableVersionMsi(
113 __in DWORD_PTR dwpData,
114 __inout BURN_VARIANT* pValue
115 );
116static HRESULT InitializeVariableCsidlFolder(
117 __in DWORD_PTR dwpData,
118 __inout BURN_VARIANT* pValue
119 );
120static HRESULT InitializeVariableWindowsVolumeFolder(
121 __in DWORD_PTR dwpData,
122 __inout BURN_VARIANT* pValue
123 );
124static HRESULT InitializeVariableTempFolder(
125 __in DWORD_PTR dwpData,
126 __inout BURN_VARIANT* pValue
127 );
128static HRESULT InitializeVariableSystemFolder(
129 __in DWORD_PTR dwpData,
130 __inout BURN_VARIANT* pValue
131 );
132static HRESULT InitializeVariablePrivileged(
133 __in DWORD_PTR dwpData,
134 __inout BURN_VARIANT* pValue
135 );
136static HRESULT InitializeSystemLanguageID(
137 __in DWORD_PTR dwpData,
138 __inout BURN_VARIANT* pValue
139 );
140static HRESULT InitializeUserUILanguageID(
141 __in DWORD_PTR dwpData,
142 __inout BURN_VARIANT* pValue
143 );
144static HRESULT InitializeUserLanguageID(
145 __in DWORD_PTR dwpData,
146 __inout BURN_VARIANT* pValue
147 );
148static HRESULT InitializeVariableString(
149 __in DWORD_PTR dwpData,
150 __inout BURN_VARIANT* pValue
151 );
152static HRESULT InitializeVariableNumeric(
153 __in DWORD_PTR dwpData,
154 __inout BURN_VARIANT* pValue
155 );
156static HRESULT InitializeVariable6432Folder(
157 __in DWORD_PTR dwpData,
158 __inout BURN_VARIANT* pValue
159 );
160static HRESULT InitializeVariableDate(
161 __in DWORD_PTR dwpData,
162 __inout BURN_VARIANT* pValue
163 );
164static HRESULT InitializeVariableInstallerName(
165 __in DWORD_PTR dwpData,
166 __inout BURN_VARIANT* pValue
167 );
168static HRESULT InitializeVariableInstallerVersion(
169 __in DWORD_PTR dwpData,
170 __inout BURN_VARIANT* pValue
171 );
172static HRESULT InitializeVariableVersion(
173 __in DWORD_PTR dwpData,
174 __inout BURN_VARIANT* pValue
175 );
176static HRESULT InitializeVariableLogonUser(
177 __in DWORD_PTR dwpData,
178 __inout BURN_VARIANT* pValue
179 );
180static HRESULT Get64bitFolderFromRegistry(
181 __in int nFolder,
182 __deref_out_z LPWSTR* psczPath
183 );
184
185#if !defined(_WIN64)
186static HRESULT InitializeVariableRegistryFolder(
187 __in DWORD_PTR dwpData,
188 __inout BURN_VARIANT* pValue
189 );
190#endif
191
192
193// function definitions
194
195extern "C" HRESULT VariableInitialize(
196 __in BURN_VARIABLES* pVariables
197 )
198{
199 HRESULT hr = S_OK;
200
201 ::InitializeCriticalSection(&pVariables->csAccess);
202
203 const BUILT_IN_VARIABLE_DECLARATION vrgBuiltInVariables[] = {
204 {L"AdminToolsFolder", InitializeVariableCsidlFolder, CSIDL_ADMINTOOLS},
205 {L"AppDataFolder", InitializeVariableCsidlFolder, CSIDL_APPDATA},
206 {L"CommonAppDataFolder", InitializeVariableCsidlFolder, CSIDL_COMMON_APPDATA},
207#if defined(_WIN64)
208 {L"CommonFiles64Folder", InitializeVariableCsidlFolder, CSIDL_PROGRAM_FILES_COMMON},
209 {L"CommonFilesFolder", InitializeVariableCsidlFolder, CSIDL_PROGRAM_FILES_COMMONX86},
210#else
211 {L"CommonFiles64Folder", InitializeVariableRegistryFolder, CSIDL_PROGRAM_FILES_COMMON},
212 {L"CommonFilesFolder", InitializeVariableCsidlFolder, CSIDL_PROGRAM_FILES_COMMON},
213#endif
214 {L"CommonFiles6432Folder", InitializeVariable6432Folder, CSIDL_PROGRAM_FILES_COMMON},
215 {L"CompatibilityMode", InitializeVariableOsInfo, OS_INFO_VARIABLE_CompatibilityMode},
216 {VARIABLE_DATE, InitializeVariableDate, 0},
217 {L"ComputerName", InitializeVariableComputerName, 0},
218 {L"DesktopFolder", InitializeVariableCsidlFolder, CSIDL_DESKTOP},
219 {L"FavoritesFolder", InitializeVariableCsidlFolder, CSIDL_FAVORITES},
220 {L"FontsFolder", InitializeVariableCsidlFolder, CSIDL_FONTS},
221 {VARIABLE_INSTALLERNAME, InitializeVariableInstallerName, 0},
222 {VARIABLE_INSTALLERVERSION, InitializeVariableInstallerVersion, 0},
223 {L"LocalAppDataFolder", InitializeVariableCsidlFolder, CSIDL_LOCAL_APPDATA},
224 {VARIABLE_LOGONUSER, InitializeVariableLogonUser, 0},
225 {L"MyPicturesFolder", InitializeVariableCsidlFolder, CSIDL_MYPICTURES},
226 {L"NTProductType", InitializeVariableOsInfo, OS_INFO_VARIABLE_NTProductType},
227 {L"NTSuiteBackOffice", InitializeVariableOsInfo, OS_INFO_VARIABLE_NTSuiteBackOffice},
228 {L"NTSuiteDataCenter", InitializeVariableOsInfo, OS_INFO_VARIABLE_NTSuiteDataCenter},
229 {L"NTSuiteEnterprise", InitializeVariableOsInfo, OS_INFO_VARIABLE_NTSuiteEnterprise},
230 {L"NTSuitePersonal", InitializeVariableOsInfo, OS_INFO_VARIABLE_NTSuitePersonal},
231 {L"NTSuiteSmallBusiness", InitializeVariableOsInfo, OS_INFO_VARIABLE_NTSuiteSmallBusiness},
232 {L"NTSuiteSmallBusinessRestricted", InitializeVariableOsInfo, OS_INFO_VARIABLE_NTSuiteSmallBusinessRestricted},
233 {L"NTSuiteWebServer", InitializeVariableOsInfo, OS_INFO_VARIABLE_NTSuiteWebServer},
234 {L"PersonalFolder", InitializeVariableCsidlFolder, CSIDL_PERSONAL},
235 {L"Privileged", InitializeVariablePrivileged, 0},
236 {L"ProcessorArchitecture", InitializeVariableSystemInfo, OS_INFO_VARIABLE_ProcessorArchitecture},
237#if defined(_WIN64)
238 {L"ProgramFiles64Folder", InitializeVariableCsidlFolder, CSIDL_PROGRAM_FILES},
239 {L"ProgramFilesFolder", InitializeVariableCsidlFolder, CSIDL_PROGRAM_FILESX86},
240#else
241 {L"ProgramFiles64Folder", InitializeVariableRegistryFolder, CSIDL_PROGRAM_FILES},
242 {L"ProgramFilesFolder", InitializeVariableCsidlFolder, CSIDL_PROGRAM_FILES},
243#endif
244 {L"ProgramFiles6432Folder", InitializeVariable6432Folder, CSIDL_PROGRAM_FILES},
245 {L"ProgramMenuFolder", InitializeVariableCsidlFolder, CSIDL_PROGRAMS},
246 {L"SendToFolder", InitializeVariableCsidlFolder, CSIDL_SENDTO},
247 {L"ServicePackLevel", InitializeVariableVersionNT, OS_INFO_VARIABLE_ServicePackLevel},
248 {L"StartMenuFolder", InitializeVariableCsidlFolder, CSIDL_STARTMENU},
249 {L"StartupFolder", InitializeVariableCsidlFolder, CSIDL_STARTUP},
250 {L"SystemFolder", InitializeVariableSystemFolder, FALSE},
251 {L"System64Folder", InitializeVariableSystemFolder, TRUE},
252 {L"SystemLanguageID", InitializeSystemLanguageID, 0},
253 {L"TempFolder", InitializeVariableTempFolder, 0},
254 {L"TemplateFolder", InitializeVariableCsidlFolder, CSIDL_TEMPLATES},
255 {L"TerminalServer", InitializeVariableOsInfo, OS_INFO_VARIABLE_TerminalServer},
256 {L"UserUILanguageID", InitializeUserUILanguageID, 0},
257 {L"UserLanguageID", InitializeUserLanguageID, 0},
258 {L"VersionMsi", InitializeVariableVersionMsi, 0},
259 {L"VersionNT", InitializeVariableVersionNT, OS_INFO_VARIABLE_VersionNT},
260 {L"VersionNT64", InitializeVariableVersionNT, OS_INFO_VARIABLE_VersionNT64},
261 {L"WindowsBuildNumber", InitializeVariableVersionNT, OS_INFO_VARIABLE_WindowsBuildNumber},
262 {L"WindowsFolder", InitializeVariableCsidlFolder, CSIDL_WINDOWS},
263 {L"WindowsVolume", InitializeVariableWindowsVolumeFolder, 0},
264 {BURN_BUNDLE_ACTION, InitializeVariableNumeric, 0, FALSE, TRUE},
265 {BURN_BUNDLE_EXECUTE_PACKAGE_CACHE_FOLDER, InitializeVariableString, NULL, FALSE, TRUE},
266 {BURN_BUNDLE_EXECUTE_PACKAGE_ACTION, InitializeVariableString, NULL, FALSE, TRUE},
267 {BURN_BUNDLE_FORCED_RESTART_PACKAGE, InitializeVariableString, NULL, TRUE, TRUE},
268 {BURN_BUNDLE_INSTALLED, InitializeVariableNumeric, 0, FALSE, TRUE},
269 {BURN_BUNDLE_ELEVATED, InitializeVariableNumeric, 0, FALSE, TRUE},
270 {BURN_BUNDLE_ACTIVE_PARENT, InitializeVariableString, NULL, FALSE, TRUE},
271 {BURN_BUNDLE_PROVIDER_KEY, InitializeVariableString, (DWORD_PTR)L"", FALSE, TRUE},
272 {BURN_BUNDLE_SOURCE_PROCESS_PATH, InitializeVariableString, NULL, FALSE, TRUE},
273 {BURN_BUNDLE_SOURCE_PROCESS_FOLDER, InitializeVariableString, NULL, FALSE, TRUE},
274 {BURN_BUNDLE_TAG, InitializeVariableString, (DWORD_PTR)L"", FALSE, TRUE},
275 {BURN_BUNDLE_UILEVEL, InitializeVariableNumeric, 0, FALSE, TRUE},
276 {BURN_BUNDLE_VERSION, InitializeVariableVersion, (DWORD_PTR)L"0", FALSE, TRUE},
277 };
278
279 for (DWORD i = 0; i < countof(vrgBuiltInVariables); ++i)
280 {
281 BUILT_IN_VARIABLE_DECLARATION* pBuiltInVariable = &vrgBuiltInVariables[i];
282
283 hr = AddBuiltInVariable(pVariables, pBuiltInVariable->wzVariable, pBuiltInVariable->pfnInitialize, pBuiltInVariable->dwpInitializeData, pBuiltInVariable->fPersist, pBuiltInVariable->fOverridable);
284 ExitOnFailure(hr, "Failed to add built-in variable: %ls.", pBuiltInVariable->wzVariable);
285 }
286
287LExit:
288 return hr;
289}
290
291extern "C" HRESULT VariablesParseFromXml(
292 __in BURN_VARIABLES* pVariables,
293 __in IXMLDOMNode* pixnBundle
294 )
295{
296 HRESULT hr = S_OK;
297 IXMLDOMNodeList* pixnNodes = NULL;
298 IXMLDOMNode* pixnNode = NULL;
299 DWORD cNodes = 0;
300 LPWSTR sczId = NULL;
301 LPWSTR scz = NULL;
302 BURN_VARIANT value = { };
303 BURN_VARIANT_TYPE valueType = BURN_VARIANT_TYPE_NONE;
304 BOOL fHidden = FALSE;
305 BOOL fPersisted = FALSE;
306 DWORD iVariable = 0;
307
308 ::EnterCriticalSection(&pVariables->csAccess);
309
310 // select variable nodes
311 hr = XmlSelectNodes(pixnBundle, L"Variable", &pixnNodes);
312 ExitOnFailure(hr, "Failed to select variable nodes.");
313
314 // get variable node count
315 hr = pixnNodes->get_length((long*)&cNodes);
316 ExitOnFailure(hr, "Failed to get variable node count.");
317
318 // parse variable elements
319 for (DWORD i = 0; i < cNodes; ++i)
320 {
321 hr = XmlNextElement(pixnNodes, &pixnNode, NULL);
322 ExitOnFailure(hr, "Failed to get next node.");
323
324 // @Id
325 hr = XmlGetAttributeEx(pixnNode, L"Id", &sczId);
326 ExitOnFailure(hr, "Failed to get @Id.");
327
328 // @Hidden
329 hr = XmlGetYesNoAttribute(pixnNode, L"Hidden", &fHidden);
330 ExitOnFailure(hr, "Failed to get @Hidden.");
331
332 // @Persisted
333 hr = XmlGetYesNoAttribute(pixnNode, L"Persisted", &fPersisted);
334 ExitOnFailure(hr, "Failed to get @Persisted.");
335
336 // @Value
337 hr = XmlGetAttributeEx(pixnNode, L"Value", &scz);
338 if (E_NOTFOUND != hr)
339 {
340 ExitOnFailure(hr, "Failed to get @Value.");
341
342 hr = BVariantSetString(&value, scz, 0, FALSE);
343 ExitOnFailure(hr, "Failed to set variant value.");
344
345 // @Type
346 hr = XmlGetAttributeEx(pixnNode, L"Type", &scz);
347 ExitOnFailure(hr, "Failed to get @Type.");
348
349 if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"formatted", -1))
350 {
351 if (!fHidden)
352 {
353 LogStringLine(REPORT_STANDARD, "Initializing formatted variable '%ls' to value '%ls'", sczId, value.sczValue);
354 }
355 valueType = BURN_VARIANT_TYPE_FORMATTED;
356 }
357 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"numeric", -1))
358 {
359 if (!fHidden)
360 {
361 LogStringLine(REPORT_STANDARD, "Initializing numeric variable '%ls' to value '%ls'", sczId, value.sczValue);
362 }
363 valueType = BURN_VARIANT_TYPE_NUMERIC;
364 }
365 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"string", -1))
366 {
367 if (!fHidden)
368 {
369 LogStringLine(REPORT_STANDARD, "Initializing string variable '%ls' to value '%ls'", sczId, value.sczValue);
370 }
371 valueType = BURN_VARIANT_TYPE_STRING;
372 }
373 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"version", -1))
374 {
375 if (!fHidden)
376 {
377 LogStringLine(REPORT_STANDARD, "Initializing version variable '%ls' to value '%ls'", sczId, value.sczValue);
378 }
379 valueType = BURN_VARIANT_TYPE_VERSION;
380 }
381 else
382 {
383 hr = E_INVALIDARG;
384 ExitOnFailure(hr, "Invalid value for @Type: %ls", scz);
385 }
386 }
387 else
388 {
389 valueType = BURN_VARIANT_TYPE_NONE;
390 }
391
392 if (fHidden)
393 {
394 LogStringLine(REPORT_STANDARD, "Initializing hidden variable '%ls'", sczId);
395 }
396
397 // change value variant to correct type
398 hr = BVariantChangeType(&value, valueType);
399 ExitOnFailure(hr, "Failed to change variant type.");
400
401 if (BURN_VARIANT_TYPE_VERSION == valueType && value.pValue->fInvalid)
402 {
403 LogId(REPORT_WARNING, MSG_VARIABLE_INVALID_VERSION, sczId);
404 }
405
406 // find existing variable
407 hr = FindVariableIndexByName(pVariables, sczId, &iVariable);
408 ExitOnFailure(hr, "Failed to find variable value '%ls'.", sczId);
409
410 // insert element if not found
411 if (S_FALSE == hr)
412 {
413 hr = InsertVariable(pVariables, sczId, iVariable);
414 ExitOnFailure(hr, "Failed to insert variable '%ls'.", sczId);
415 }
416 else if (BURN_VARIABLE_INTERNAL_TYPE_NORMAL < pVariables->rgVariables[iVariable].internalType)
417 {
418 hr = E_INVALIDARG;
419 ExitOnRootFailure(hr, "Attempt to set built-in variable value: %ls", sczId);
420 }
421 pVariables->rgVariables[iVariable].fHidden = fHidden;
422 pVariables->rgVariables[iVariable].fPersisted = fPersisted;
423
424 // update variable value
425 hr = BVariantSetValue(&pVariables->rgVariables[iVariable].Value, &value);
426 ExitOnFailure(hr, "Failed to set value of variable: %ls", sczId);
427
428 // prepare next iteration
429 ReleaseNullObject(pixnNode);
430 BVariantUninitialize(&value);
431 ReleaseNullStrSecure(scz);
432 }
433
434LExit:
435 ::LeaveCriticalSection(&pVariables->csAccess);
436
437 ReleaseObject(pixnNodes);
438 ReleaseObject(pixnNode);
439 ReleaseStr(scz);
440 ReleaseStr(sczId);
441 BVariantUninitialize(&value);
442
443 return hr;
444}
445
446extern "C" void VariablesUninitialize(
447 __in BURN_VARIABLES* pVariables
448 )
449{
450 ::DeleteCriticalSection(&pVariables->csAccess);
451
452 if (pVariables->rgVariables)
453 {
454 for (DWORD i = 0; i < pVariables->cVariables; ++i)
455 {
456 BURN_VARIABLE* pVariable = &pVariables->rgVariables[i];
457 if (pVariable)
458 {
459 ReleaseStr(pVariable->sczName);
460 BVariantUninitialize(&pVariable->Value);
461 }
462 }
463 MemFree(pVariables->rgVariables);
464 }
465}
466
467extern "C" void VariablesDump(
468 __in BURN_VARIABLES* pVariables
469 )
470{
471 HRESULT hr = S_OK;
472 LPWSTR sczValue = NULL;
473
474 for (DWORD i = 0; i < pVariables->cVariables; ++i)
475 {
476 BURN_VARIABLE* pVariable = &pVariables->rgVariables[i];
477 if (pVariable && BURN_VARIANT_TYPE_NONE != pVariable->Value.Type)
478 {
479 hr = StrAllocFormatted(&sczValue, L"%ls = [%ls]", pVariable->sczName, pVariable->sczName);
480 if (SUCCEEDED(hr))
481 {
482 if (pVariable->fHidden)
483 {
484 hr = VariableFormatStringObfuscated(pVariables, sczValue, &sczValue, NULL);
485 }
486 else
487 {
488 hr = VariableFormatString(pVariables, sczValue, &sczValue, NULL);
489 }
490 }
491
492 if (FAILED(hr))
493 {
494 // already logged; best-effort to dump the rest on our way out the door
495 continue;
496 }
497
498 LogId(REPORT_VERBOSE, MSG_VARIABLE_DUMP, sczValue);
499
500 ReleaseNullStrSecure(sczValue);
501 }
502 }
503
504 StrSecureZeroFreeString(sczValue);
505}
506
507extern "C" HRESULT VariableGetNumeric(
508 __in BURN_VARIABLES* pVariables,
509 __in_z LPCWSTR wzVariable,
510 __out LONGLONG* pllValue
511 )
512{
513 HRESULT hr = S_OK;
514 BURN_VARIABLE* pVariable = NULL;
515
516 ::EnterCriticalSection(&pVariables->csAccess);
517
518 hr = GetVariable(pVariables, wzVariable, &pVariable);
519 if (SUCCEEDED(hr) && BURN_VARIANT_TYPE_NONE == pVariable->Value.Type)
520 {
521 ExitFunction1(hr = E_NOTFOUND);
522 }
523 else if (E_NOTFOUND == hr)
524 {
525 ExitFunction();
526 }
527 ExitOnFailure(hr, "Failed to get value of variable: %ls", wzVariable);
528
529 hr = BVariantGetNumeric(&pVariable->Value, pllValue);
530 ExitOnFailure(hr, "Failed to get value as numeric for variable: %ls", wzVariable);
531
532LExit:
533 ::LeaveCriticalSection(&pVariables->csAccess);
534
535 return hr;
536}
537
538extern "C" HRESULT VariableGetString(
539 __in BURN_VARIABLES* pVariables,
540 __in_z LPCWSTR wzVariable,
541 __out_z LPWSTR* psczValue
542 )
543{
544 HRESULT hr = S_OK;
545 BURN_VARIABLE* pVariable = NULL;
546
547 ::EnterCriticalSection(&pVariables->csAccess);
548
549 hr = GetVariable(pVariables, wzVariable, &pVariable);
550 if (SUCCEEDED(hr) && BURN_VARIANT_TYPE_NONE == pVariable->Value.Type)
551 {
552 ExitFunction1(hr = E_NOTFOUND);
553 }
554 else if (E_NOTFOUND == hr)
555 {
556 ExitFunction();
557 }
558 ExitOnFailure(hr, "Failed to get value of variable: %ls", wzVariable);
559
560 hr = BVariantGetString(&pVariable->Value, psczValue);
561 ExitOnFailure(hr, "Failed to get value as string for variable: %ls", wzVariable);
562
563LExit:
564 ::LeaveCriticalSection(&pVariables->csAccess);
565
566 return hr;
567}
568
569extern "C" HRESULT VariableGetVersion(
570 __in BURN_VARIABLES* pVariables,
571 __in_z LPCWSTR wzVariable,
572 __in VERUTIL_VERSION** ppValue
573 )
574{
575 HRESULT hr = S_OK;
576 BURN_VARIABLE* pVariable = NULL;
577
578 ::EnterCriticalSection(&pVariables->csAccess);
579
580 hr = GetVariable(pVariables, wzVariable, &pVariable);
581 if (SUCCEEDED(hr) && BURN_VARIANT_TYPE_NONE == pVariable->Value.Type)
582 {
583 ExitFunction1(hr = E_NOTFOUND);
584 }
585 else if (E_NOTFOUND == hr)
586 {
587 ExitFunction();
588 }
589 ExitOnFailure(hr, "Failed to get value of variable: %ls", wzVariable);
590
591 hr = BVariantGetVersionHidden(&pVariable->Value, pVariable->fHidden, ppValue);
592 ExitOnFailure(hr, "Failed to get value as version for variable: %ls", wzVariable);
593
594LExit:
595 ::LeaveCriticalSection(&pVariables->csAccess);
596
597 return hr;
598}
599
600extern "C" HRESULT VariableGetVariant(
601 __in BURN_VARIABLES* pVariables,
602 __in_z LPCWSTR wzVariable,
603 __in BURN_VARIANT* pValue
604 )
605{
606 HRESULT hr = S_OK;
607 BURN_VARIABLE* pVariable = NULL;
608
609 ::EnterCriticalSection(&pVariables->csAccess);
610
611 hr = GetVariable(pVariables, wzVariable, &pVariable);
612 if (E_NOTFOUND == hr)
613 {
614 ExitFunction();
615 }
616 ExitOnFailure(hr, "Failed to get value of variable: %ls", wzVariable);
617
618 hr = BVariantCopy(&pVariable->Value, pValue);
619 ExitOnFailure(hr, "Failed to copy value of variable: %ls", wzVariable);
620
621LExit:
622 ::LeaveCriticalSection(&pVariables->csAccess);
623
624 return hr;
625}
626
627extern "C" HRESULT VariableGetFormatted(
628 __in BURN_VARIABLES* pVariables,
629 __in_z LPCWSTR wzVariable,
630 __out_z LPWSTR* psczValue,
631 __out BOOL* pfContainsHiddenVariable
632 )
633{
634 HRESULT hr = S_OK;
635
636 if (pfContainsHiddenVariable)
637 {
638 *pfContainsHiddenVariable = FALSE;
639 }
640
641 hr = GetFormatted(pVariables, wzVariable, psczValue, pfContainsHiddenVariable);
642
643 return hr;
644}
645
646extern "C" HRESULT VariableSetNumeric(
647 __in BURN_VARIABLES* pVariables,
648 __in_z LPCWSTR wzVariable,
649 __in LONGLONG llValue,
650 __in BOOL fOverwriteBuiltIn
651 )
652{
653 BURN_VARIANT variant = { };
654
655 variant.llValue = llValue;
656 variant.Type = BURN_VARIANT_TYPE_NUMERIC;
657
658 return SetVariableValue(pVariables, wzVariable, &variant, fOverwriteBuiltIn ? SET_VARIABLE_OVERRIDE_BUILTIN : SET_VARIABLE_NOT_BUILTIN, TRUE);
659}
660
661extern "C" HRESULT VariableSetString(
662 __in BURN_VARIABLES* pVariables,
663 __in_z LPCWSTR wzVariable,
664 __in_z_opt LPCWSTR wzValue,
665 __in BOOL fOverwriteBuiltIn,
666 __in BOOL fFormatted
667 )
668{
669 BURN_VARIANT variant = { };
670
671 variant.sczValue = (LPWSTR)wzValue;
672 variant.Type = fFormatted ? BURN_VARIANT_TYPE_FORMATTED : BURN_VARIANT_TYPE_STRING;
673
674 return SetVariableValue(pVariables, wzVariable, &variant, fOverwriteBuiltIn ? SET_VARIABLE_OVERRIDE_BUILTIN : SET_VARIABLE_NOT_BUILTIN, TRUE);
675}
676
677extern "C" HRESULT VariableSetVersion(
678 __in BURN_VARIABLES* pVariables,
679 __in_z LPCWSTR wzVariable,
680 __in VERUTIL_VERSION* pValue,
681 __in BOOL fOverwriteBuiltIn
682 )
683{
684 BURN_VARIANT variant = { };
685
686 variant.pValue = pValue;
687 variant.Type = BURN_VARIANT_TYPE_VERSION;
688
689 return SetVariableValue(pVariables, wzVariable, &variant, fOverwriteBuiltIn ? SET_VARIABLE_OVERRIDE_BUILTIN : SET_VARIABLE_NOT_BUILTIN, TRUE);
690}
691
692extern "C" HRESULT VariableSetVariant(
693 __in BURN_VARIABLES * pVariables,
694 __in_z LPCWSTR wzVariable,
695 __in BURN_VARIANT * pVariant
696 )
697{
698 return SetVariableValue(pVariables, wzVariable, pVariant, SET_VARIABLE_NOT_BUILTIN, TRUE);
699}
700
701extern "C" HRESULT VariableFormatString(
702 __in BURN_VARIABLES* pVariables,
703 __in_z LPCWSTR wzIn,
704 __out_z_opt LPWSTR* psczOut,
705 __out_opt SIZE_T* pcchOut
706 )
707{
708 return FormatString(pVariables, wzIn, psczOut, pcchOut, FALSE, NULL);
709}
710
711extern "C" HRESULT VariableFormatStringObfuscated(
712 __in BURN_VARIABLES* pVariables,
713 __in_z LPCWSTR wzIn,
714 __out_z_opt LPWSTR* psczOut,
715 __out_opt SIZE_T* pcchOut
716 )
717{
718 return FormatString(pVariables, wzIn, psczOut, pcchOut, TRUE, NULL);
719}
720
721extern "C" HRESULT VariableEscapeString(
722 __in_z LPCWSTR wzIn,
723 __out_z LPWSTR* psczOut
724 )
725{
726 HRESULT hr = S_OK;
727 LPCWSTR wzRead = NULL;
728 LPWSTR pwzEscaped = NULL;
729 LPWSTR pwz = NULL;
730 SIZE_T i = 0;
731
732 // allocate buffer for escaped string
733 hr = StrAlloc(&pwzEscaped, lstrlenW(wzIn) + 1);
734 ExitOnFailure(hr, "Failed to allocate buffer for escaped string.");
735
736 // read through string and move characters, inserting escapes as needed
737 wzRead = wzIn;
738 for (;;)
739 {
740 // find next character needing escaping
741 i = wcscspn(wzRead, L"[]{}");
742
743 // copy skipped characters
744 if (0 < i)
745 {
746 hr = StrAllocConcat(&pwzEscaped, wzRead, i);
747 ExitOnFailure(hr, "Failed to append characters.");
748 }
749
750 if (L'\0' == wzRead[i])
751 {
752 break; // end reached
753 }
754
755 // escape character
756 hr = StrAllocFormatted(&pwz, L"[\\%c]", wzRead[i]);
757 ExitOnFailure(hr, "Failed to format escape sequence.");
758
759 hr = StrAllocConcat(&pwzEscaped, pwz, 0);
760 ExitOnFailure(hr, "Failed to append escape sequence.");
761
762 // update read pointer
763 wzRead += i + 1;
764 }
765
766 // return value
767 hr = StrAllocString(psczOut, pwzEscaped, 0);
768 ExitOnFailure(hr, "Failed to copy string.");
769
770LExit:
771 ReleaseStr(pwzEscaped);
772 ReleaseStr(pwz);
773 return hr;
774}
775
776extern "C" HRESULT VariableSerialize(
777 __in BURN_VARIABLES* pVariables,
778 __in BOOL fPersisting,
779 __inout BYTE** ppbBuffer,
780 __inout SIZE_T* piBuffer
781 )
782{
783 HRESULT hr = S_OK;
784 BOOL fIncluded = FALSE;
785 LONGLONG ll = 0;
786 LPWSTR scz = NULL;
787
788 ::EnterCriticalSection(&pVariables->csAccess);
789
790 // Write variable count.
791 hr = BuffWriteNumber(ppbBuffer, piBuffer, pVariables->cVariables);
792 ExitOnFailure(hr, "Failed to write variable count.");
793
794 // Write variables.
795 for (DWORD i = 0; i < pVariables->cVariables; ++i)
796 {
797 BURN_VARIABLE* pVariable = &pVariables->rgVariables[i];
798
799 // If we aren't persisting, include only variables that aren't rejected by the elevated process.
800 // If we are persisting, include only variables that should be persisted.
801 fIncluded = (!fPersisting && BURN_VARIABLE_INTERNAL_TYPE_BUILTIN != pVariable->internalType) ||
802 (fPersisting && pVariable->fPersisted);
803
804 // Write included flag.
805 hr = BuffWriteNumber(ppbBuffer, piBuffer, (DWORD)fIncluded);
806 ExitOnFailure(hr, "Failed to write included flag.");
807
808 if (!fIncluded)
809 {
810 continue;
811 }
812
813 // Write variable name.
814 hr = BuffWriteString(ppbBuffer, piBuffer, pVariable->sczName);
815 ExitOnFailure(hr, "Failed to write variable name.");
816
817 // Write variable value type.
818 hr = BuffWriteNumber(ppbBuffer, piBuffer, (DWORD)pVariable->Value.Type);
819 ExitOnFailure(hr, "Failed to write variable value type.");
820
821 // Write variable value.
822 switch (pVariable->Value.Type)
823 {
824 case BURN_VARIANT_TYPE_NONE:
825 break;
826 case BURN_VARIANT_TYPE_NUMERIC:
827 hr = BVariantGetNumeric(&pVariable->Value, &ll);
828 ExitOnFailure(hr, "Failed to get numeric.");
829
830 hr = BuffWriteNumber64(ppbBuffer, piBuffer, static_cast<DWORD64>(ll));
831 ExitOnFailure(hr, "Failed to write variable value as number.");
832
833 SecureZeroMemory(&ll, sizeof(ll));
834 break;
835 case BURN_VARIANT_TYPE_VERSION: __fallthrough;
836 case BURN_VARIANT_TYPE_FORMATTED: __fallthrough;
837 case BURN_VARIANT_TYPE_STRING:
838 hr = BVariantGetString(&pVariable->Value, &scz);
839 ExitOnFailure(hr, "Failed to get string.");
840
841 hr = BuffWriteString(ppbBuffer, piBuffer, scz);
842 ExitOnFailure(hr, "Failed to write variable value as string.");
843
844 ReleaseNullStrSecure(scz);
845 break;
846 default:
847 hr = E_INVALIDARG;
848 ExitOnFailure(hr, "Unsupported variable type.");
849 }
850 }
851
852LExit:
853 ::LeaveCriticalSection(&pVariables->csAccess);
854 SecureZeroMemory(&ll, sizeof(ll));
855 StrSecureZeroFreeString(scz);
856
857 return hr;
858}
859
860extern "C" HRESULT VariableDeserialize(
861 __in BURN_VARIABLES* pVariables,
862 __in BOOL fWasPersisted,
863 __in_bcount(cbBuffer) BYTE* pbBuffer,
864 __in SIZE_T cbBuffer,
865 __inout SIZE_T* piBuffer
866 )
867{
868 HRESULT hr = S_OK;
869 DWORD cVariables = 0;
870 LPWSTR sczName = NULL;
871 BOOL fIncluded = FALSE;
872 BURN_VARIANT value = { };
873 LPWSTR scz = NULL;
874 DWORD64 qw = 0;
875 VERUTIL_VERSION* pVersion = NULL;
876
877 ::EnterCriticalSection(&pVariables->csAccess);
878
879 // Read variable count.
880 hr = BuffReadNumber(pbBuffer, cbBuffer, piBuffer, &cVariables);
881 ExitOnFailure(hr, "Failed to read variable count.");
882
883 // Read variables.
884 for (DWORD i = 0; i < cVariables; ++i)
885 {
886 // Read variable included flag.
887 hr = BuffReadNumber(pbBuffer, cbBuffer, piBuffer, (DWORD*)&fIncluded);
888 ExitOnFailure(hr, "Failed to read variable included flag.");
889
890 if (!fIncluded)
891 {
892 continue; // if variable is not included, skip.
893 }
894
895 // Read variable name.
896 hr = BuffReadString(pbBuffer, cbBuffer, piBuffer, &sczName);
897 ExitOnFailure(hr, "Failed to read variable name.");
898
899 // Read variable value type.
900 hr = BuffReadNumber(pbBuffer, cbBuffer, piBuffer, (DWORD*)&value.Type);
901 ExitOnFailure(hr, "Failed to read variable value type.");
902
903 // Read variable value.
904 switch (value.Type)
905 {
906 case BURN_VARIANT_TYPE_NONE:
907 break;
908 case BURN_VARIANT_TYPE_NUMERIC:
909 hr = BuffReadNumber64(pbBuffer, cbBuffer, piBuffer, &qw);
910 ExitOnFailure(hr, "Failed to read variable value as number.");
911
912 hr = BVariantSetNumeric(&value, static_cast<LONGLONG>(qw));
913 ExitOnFailure(hr, "Failed to set variable value.");
914
915 SecureZeroMemory(&qw, sizeof(qw));
916 break;
917 case BURN_VARIANT_TYPE_VERSION:
918 hr = BuffReadString(pbBuffer, cbBuffer, piBuffer, &scz);
919 ExitOnFailure(hr, "Failed to read variable value as string.");
920
921 hr = VerParseVersion(scz, 0, FALSE, &pVersion);
922 ExitOnFailure(hr, "Failed to parse variable value as version.");
923
924 hr = BVariantSetVersion(&value, pVersion);
925 ExitOnFailure(hr, "Failed to set variable value.");
926
927 SecureZeroMemory(&qw, sizeof(qw));
928 break;
929 case BURN_VARIANT_TYPE_FORMATTED: __fallthrough;
930 case BURN_VARIANT_TYPE_STRING:
931 hr = BuffReadString(pbBuffer, cbBuffer, piBuffer, &scz);
932 ExitOnFailure(hr, "Failed to read variable value as string.");
933
934 hr = BVariantSetString(&value, scz, NULL, BURN_VARIANT_TYPE_FORMATTED == value.Type);
935 ExitOnFailure(hr, "Failed to set variable value.");
936
937 ReleaseNullStrSecure(scz);
938 break;
939 default:
940 hr = E_INVALIDARG;
941 ExitOnFailure(hr, "Unsupported variable type.");
942 }
943
944 // Set variable.
945 hr = SetVariableValue(pVariables, sczName, &value, fWasPersisted ? SET_VARIABLE_OVERRIDE_PERSISTED_BUILTINS : SET_VARIABLE_ANY, FALSE);
946 ExitOnFailure(hr, "Failed to set variable.");
947
948 // Clean up.
949 BVariantUninitialize(&value);
950 }
951
952LExit:
953 ::LeaveCriticalSection(&pVariables->csAccess);
954
955 ReleaseVerutilVersion(pVersion);
956 ReleaseStr(sczName);
957 BVariantUninitialize(&value);
958 SecureZeroMemory(&qw, sizeof(qw));
959 StrSecureZeroFreeString(scz);
960
961 return hr;
962}
963
964extern "C" HRESULT VariableStrAlloc(
965 __in BOOL fZeroOnRealloc,
966 __deref_out_ecount_part(cch, 0) LPWSTR* ppwz,
967 __in DWORD_PTR cch
968 )
969{
970 HRESULT hr = S_OK;
971
972 if (fZeroOnRealloc)
973 {
974 hr = StrAllocSecure(ppwz, cch);
975 }
976 else
977 {
978 hr = StrAlloc(ppwz, cch);
979 }
980
981 return hr;
982}
983
984extern "C" HRESULT VariableStrAllocString(
985 __in BOOL fZeroOnRealloc,
986 __deref_out_ecount_z(cchSource + 1) LPWSTR* ppwz,
987 __in_z LPCWSTR wzSource,
988 __in DWORD_PTR cchSource
989 )
990{
991 HRESULT hr = S_OK;
992
993 if (fZeroOnRealloc)
994 {
995 hr = StrAllocStringSecure(ppwz, wzSource, cchSource);
996 }
997 else
998 {
999 hr = StrAllocString(ppwz, wzSource, cchSource);
1000 }
1001
1002 return hr;
1003}
1004
1005extern "C" HRESULT VariableStrAllocConcat(
1006 __in BOOL fZeroOnRealloc,
1007 __deref_out_z LPWSTR* ppwz,
1008 __in_z LPCWSTR wzSource,
1009 __in DWORD_PTR cchSource
1010 )
1011{
1012 HRESULT hr = S_OK;
1013
1014 if (fZeroOnRealloc)
1015 {
1016 hr = StrAllocConcatSecure(ppwz, wzSource, cchSource);
1017 }
1018 else
1019 {
1020 hr = StrAllocConcat(ppwz, wzSource, cchSource);
1021 }
1022
1023 return hr;
1024}
1025
1026extern "C" HRESULT __cdecl VariableStrAllocFormatted(
1027 __in BOOL fZeroOnRealloc,
1028 __deref_out_z LPWSTR* ppwz,
1029 __in __format_string LPCWSTR wzFormat,
1030 ...
1031 )
1032{
1033 HRESULT hr = S_OK;
1034 va_list args;
1035
1036 va_start(args, wzFormat);
1037 if (fZeroOnRealloc)
1038 {
1039 hr = StrAllocFormattedArgsSecure(ppwz, wzFormat, args);
1040 }
1041 else
1042 {
1043 hr = StrAllocFormattedArgs(ppwz, wzFormat, args);
1044 }
1045 va_end(args);
1046
1047 return hr;
1048}
1049
1050extern "C" HRESULT VariableIsHidden(
1051 __in BURN_VARIABLES* pVariables,
1052 __in_z LPCWSTR wzVariable,
1053 __out BOOL* pfHidden
1054 )
1055{
1056 HRESULT hr = S_OK;
1057 BURN_VARIABLE* pVariable = NULL;
1058
1059 ::EnterCriticalSection(&pVariables->csAccess);
1060
1061 hr = GetVariable(pVariables, wzVariable, &pVariable);
1062 if (E_NOTFOUND == hr)
1063 {
1064 // A missing variable does not need its data hidden.
1065 *pfHidden = FALSE;
1066
1067 ExitFunction1(hr = S_OK);
1068 }
1069 ExitOnFailure(hr, "Failed to get visibility of variable: %ls", wzVariable);
1070
1071 *pfHidden = pVariable->fHidden;
1072
1073LExit:
1074 ::LeaveCriticalSection(&pVariables->csAccess);
1075
1076 return hr;
1077}
1078
1079
1080// internal function definitions
1081
1082static HRESULT FormatString(
1083 __in BURN_VARIABLES* pVariables,
1084 __in_z LPCWSTR wzIn,
1085 __out_z_opt LPWSTR* psczOut,
1086 __out_opt SIZE_T* pcchOut,
1087 __in BOOL fObfuscateHiddenVariables,
1088 __out BOOL* pfContainsHiddenVariable
1089 )
1090{
1091 HRESULT hr = S_OK;
1092 DWORD er = ERROR_SUCCESS;
1093 LPWSTR sczUnformatted = NULL;
1094 LPWSTR sczFormat = NULL;
1095 LPCWSTR wzRead = NULL;
1096 LPCWSTR wzOpen = NULL;
1097 LPCWSTR wzClose = NULL;
1098 LPWSTR scz = NULL;
1099 LPWSTR* rgVariables = NULL;
1100 DWORD cVariables = 0;
1101 DWORD cch = 0;
1102 size_t cchIn = 0;
1103 BOOL fHidden = FALSE;
1104 MSIHANDLE hRecord = NULL;
1105
1106 ::EnterCriticalSection(&pVariables->csAccess);
1107
1108 // allocate buffer for format string
1109 hr = ::StringCchLengthW(wzIn, STRSAFE_MAX_LENGTH, &cchIn);
1110 ExitOnFailure(hr, "Failed to length of format string.");
1111
1112 hr = StrAlloc(&sczFormat, cchIn + 1);
1113 ExitOnFailure(hr, "Failed to allocate buffer for format string.");
1114
1115 // read out variables from the unformatted string and build a format string
1116 wzRead = wzIn;
1117 for (;;)
1118 {
1119 // scan for opening '['
1120 wzOpen = wcschr(wzRead, L'[');
1121 if (!wzOpen)
1122 {
1123 // end reached, append the remainder of the string and end loop
1124 hr = VariableStrAllocConcat(!fObfuscateHiddenVariables, &sczFormat, wzRead, 0);
1125 ExitOnFailure(hr, "Failed to append string.");
1126 break;
1127 }
1128
1129 // scan for closing ']'
1130 wzClose = wcschr(wzOpen + 1, L']');
1131 if (!wzClose)
1132 {
1133 // end reached, treat unterminated expander as literal
1134 hr = VariableStrAllocConcat(!fObfuscateHiddenVariables, &sczFormat, wzRead, 0);
1135 ExitOnFailure(hr, "Failed to append string.");
1136 break;
1137 }
1138 cch = (DWORD)(wzClose - wzOpen - 1);
1139
1140 if (0 == cch)
1141 {
1142 // blank, copy all text including the terminator
1143 hr = VariableStrAllocConcat(!fObfuscateHiddenVariables, &sczFormat, wzRead, (DWORD_PTR)(wzClose - wzRead) + 1);
1144 ExitOnFailure(hr, "Failed to append string.");
1145 }
1146 else
1147 {
1148 // append text preceding expander
1149 if (wzOpen > wzRead)
1150 {
1151 hr = VariableStrAllocConcat(!fObfuscateHiddenVariables, &sczFormat, wzRead, (DWORD_PTR)(wzOpen - wzRead));
1152 ExitOnFailure(hr, "Failed to append string.");
1153 }
1154
1155 // get variable name
1156 hr = VariableStrAllocString(!fObfuscateHiddenVariables, &scz, wzOpen + 1, cch);
1157 ExitOnFailure(hr, "Failed to get variable name.");
1158
1159 // allocate space in variable array
1160 if (rgVariables)
1161 {
1162 LPVOID pv = MemReAlloc(rgVariables, sizeof(LPWSTR) * (cVariables + 1), TRUE);
1163 ExitOnNull(pv, hr, E_OUTOFMEMORY, "Failed to reallocate variable array.");
1164 rgVariables = (LPWSTR*)pv;
1165 }
1166 else
1167 {
1168 rgVariables = (LPWSTR*)MemAlloc(sizeof(LPWSTR) * (cVariables + 1), TRUE);
1169 ExitOnNull(rgVariables, hr, E_OUTOFMEMORY, "Failed to allocate variable array.");
1170 }
1171
1172 // set variable value
1173 if (2 <= cch && L'\\' == wzOpen[1])
1174 {
1175 // escape sequence, copy character
1176 hr = VariableStrAllocString(!fObfuscateHiddenVariables, &rgVariables[cVariables], &wzOpen[2], 1);
1177 }
1178 else
1179 {
1180 hr = VariableIsHidden(pVariables, scz, &fHidden);
1181 ExitOnFailure(hr, "Failed to determine variable visibility: '%ls'.", scz);
1182
1183 if (pfContainsHiddenVariable)
1184 {
1185 *pfContainsHiddenVariable |= fHidden;
1186 }
1187
1188 if (fObfuscateHiddenVariables && fHidden)
1189 {
1190 hr = StrAllocString(&rgVariables[cVariables], L"*****", 0);
1191 }
1192 else
1193 {
1194 // get formatted variable value
1195 hr = GetFormatted(pVariables, scz, &rgVariables[cVariables], pfContainsHiddenVariable);
1196 if (E_NOTFOUND == hr) // variable not found
1197 {
1198 hr = StrAllocStringSecure(&rgVariables[cVariables], L"", 0);
1199 }
1200 }
1201 }
1202 ExitOnFailure(hr, "Failed to set variable value.");
1203 ++cVariables;
1204
1205 // append placeholder to format string
1206 hr = VariableStrAllocFormatted(!fObfuscateHiddenVariables, &scz, L"[%d]", cVariables);
1207 ExitOnFailure(hr, "Failed to format placeholder string.");
1208
1209 hr = VariableStrAllocConcat(!fObfuscateHiddenVariables, &sczFormat, scz, 0);
1210 ExitOnFailure(hr, "Failed to append placeholder.");
1211 }
1212
1213 // update read pointer
1214 wzRead = wzClose + 1;
1215 }
1216
1217 // create record
1218 hRecord = ::MsiCreateRecord(cVariables);
1219 ExitOnNull(hRecord, hr, E_OUTOFMEMORY, "Failed to allocate record.");
1220
1221 // set format string
1222 er = ::MsiRecordSetStringW(hRecord, 0, sczFormat);
1223 ExitOnWin32Error(er, hr, "Failed to set record format string.");
1224
1225 // copy record fields
1226 for (DWORD i = 0; i < cVariables; ++i)
1227 {
1228 if (*rgVariables[i]) // not setting if blank
1229 {
1230 er = ::MsiRecordSetStringW(hRecord, i + 1, rgVariables[i]);
1231 ExitOnWin32Error(er, hr, "Failed to set record string.");
1232 }
1233 }
1234
1235 // get formatted character count
1236 cch = 0;
1237#pragma prefast(push)
1238#pragma prefast(disable:6298)
1239 er = ::MsiFormatRecordW(NULL, hRecord, L"", &cch);
1240#pragma prefast(pop)
1241 if (ERROR_MORE_DATA != er)
1242 {
1243 ExitOnWin32Error(er, hr, "Failed to get formatted length.");
1244 }
1245
1246 // return formatted string
1247 if (psczOut)
1248 {
1249 hr = VariableStrAlloc(!fObfuscateHiddenVariables, &scz, ++cch);
1250 ExitOnFailure(hr, "Failed to allocate string.");
1251
1252 er = ::MsiFormatRecordW(NULL, hRecord, scz, &cch);
1253 ExitOnWin32Error(er, hr, "Failed to format record.");
1254
1255 hr = VariableStrAllocString(!fObfuscateHiddenVariables, psczOut, scz, 0);
1256 ExitOnFailure(hr, "Failed to copy string.");
1257 }
1258
1259 // return character count
1260 if (pcchOut)
1261 {
1262 *pcchOut = cch;
1263 }
1264
1265LExit:
1266 ::LeaveCriticalSection(&pVariables->csAccess);
1267
1268 if (rgVariables)
1269 {
1270 for (DWORD i = 0; i < cVariables; ++i)
1271 {
1272 if (fObfuscateHiddenVariables)
1273 {
1274 ReleaseStr(rgVariables[i]);
1275 }
1276 else
1277 {
1278 StrSecureZeroFreeString(rgVariables[i]);
1279 }
1280 }
1281 MemFree(rgVariables);
1282 }
1283
1284 if (hRecord)
1285 {
1286 ::MsiCloseHandle(hRecord);
1287 }
1288
1289 if (fObfuscateHiddenVariables)
1290 {
1291 ReleaseStr(sczUnformatted);
1292 ReleaseStr(sczFormat);
1293 ReleaseStr(scz);
1294 }
1295 else
1296 {
1297 StrSecureZeroFreeString(sczUnformatted);
1298 StrSecureZeroFreeString(sczFormat);
1299 StrSecureZeroFreeString(scz);
1300 }
1301
1302 return hr;
1303}
1304
1305static HRESULT GetFormatted(
1306 __in BURN_VARIABLES* pVariables,
1307 __in_z LPCWSTR wzVariable,
1308 __out_z LPWSTR* psczValue,
1309 __out BOOL* pfContainsHiddenVariable
1310 )
1311{
1312 HRESULT hr = S_OK;
1313 BURN_VARIABLE* pVariable = NULL;
1314 LPWSTR scz = NULL;
1315
1316 ::EnterCriticalSection(&pVariables->csAccess);
1317
1318 hr = GetVariable(pVariables, wzVariable, &pVariable);
1319 if (SUCCEEDED(hr) && BURN_VARIANT_TYPE_NONE == pVariable->Value.Type)
1320 {
1321 ExitFunction1(hr = E_NOTFOUND);
1322 }
1323 else if (E_NOTFOUND == hr)
1324 {
1325 ExitFunction();
1326 }
1327 ExitOnFailure(hr, "Failed to get variable: %ls", wzVariable);
1328
1329 if (pfContainsHiddenVariable)
1330 {
1331 *pfContainsHiddenVariable |= pVariable->fHidden;
1332 }
1333
1334 if (BURN_VARIANT_TYPE_FORMATTED == pVariable->Value.Type)
1335 {
1336 hr = BVariantGetString(&pVariable->Value, &scz);
1337 ExitOnFailure(hr, "Failed to get unformatted string.");
1338
1339 hr = FormatString(pVariables, scz, psczValue, NULL, FALSE, pfContainsHiddenVariable);
1340 ExitOnFailure(hr, "Failed to format value '%ls' of variable: %ls", pVariable->fHidden ? L"*****" : pVariable->Value.sczValue, wzVariable);
1341 }
1342 else
1343 {
1344 hr = BVariantGetString(&pVariable->Value, psczValue);
1345 ExitOnFailure(hr, "Failed to get value as string for variable: %ls", wzVariable);
1346 }
1347
1348LExit:
1349 ::LeaveCriticalSection(&pVariables->csAccess);
1350 StrSecureZeroFreeString(scz);
1351
1352 return hr;
1353}
1354
1355static HRESULT AddBuiltInVariable(
1356 __in BURN_VARIABLES* pVariables,
1357 __in LPCWSTR wzVariable,
1358 __in PFN_INITIALIZEVARIABLE pfnInitialize,
1359 __in DWORD_PTR dwpInitializeData,
1360 __in BOOL fPersist,
1361 __in BOOL fOverridable
1362 )
1363{
1364 HRESULT hr = S_OK;
1365 DWORD iVariable = 0;
1366 BURN_VARIABLE* pVariable = NULL;
1367
1368 hr = FindVariableIndexByName(pVariables, wzVariable, &iVariable);
1369 ExitOnFailure(hr, "Failed to find variable value.");
1370
1371 // insert element if not found
1372 if (S_FALSE == hr)
1373 {
1374 hr = InsertVariable(pVariables, wzVariable, iVariable);
1375 ExitOnFailure(hr, "Failed to insert variable.");
1376 }
1377
1378 // set variable values
1379 pVariable = &pVariables->rgVariables[iVariable];
1380 pVariable->fPersisted = fPersist;
1381 pVariable->internalType = fOverridable ? BURN_VARIABLE_INTERNAL_TYPE_OVERRIDABLE_BUILTIN : BURN_VARIABLE_INTERNAL_TYPE_BUILTIN;
1382 pVariable->pfnInitialize = pfnInitialize;
1383 pVariable->dwpInitializeData = dwpInitializeData;
1384
1385LExit:
1386 return hr;
1387}
1388
1389static HRESULT GetVariable(
1390 __in BURN_VARIABLES* pVariables,
1391 __in_z LPCWSTR wzVariable,
1392 __out BURN_VARIABLE** ppVariable
1393 )
1394{
1395 HRESULT hr = S_OK;
1396 DWORD iVariable = 0;
1397 BURN_VARIABLE* pVariable = NULL;
1398
1399 hr = FindVariableIndexByName(pVariables, wzVariable, &iVariable);
1400 ExitOnFailure(hr, "Failed to find variable value '%ls'.", wzVariable);
1401
1402 if (S_FALSE == hr)
1403 {
1404 ExitFunction1(hr = E_NOTFOUND);
1405 }
1406
1407 pVariable = &pVariables->rgVariables[iVariable];
1408
1409 // initialize built-in variable
1410 if (BURN_VARIANT_TYPE_NONE == pVariable->Value.Type && BURN_VARIABLE_INTERNAL_TYPE_NORMAL < pVariable->internalType)
1411 {
1412 hr = pVariable->pfnInitialize(pVariable->dwpInitializeData, &pVariable->Value);
1413 ExitOnFailure(hr, "Failed to initialize built-in variable value '%ls'.", wzVariable);
1414 }
1415
1416 *ppVariable = pVariable;
1417
1418LExit:
1419 return hr;
1420}
1421
1422static HRESULT FindVariableIndexByName(
1423 __in BURN_VARIABLES* pVariables,
1424 __in_z LPCWSTR wzVariable,
1425 __out DWORD* piVariable
1426 )
1427{
1428 HRESULT hr = S_OK;
1429 DWORD iRangeFirst = 0;
1430 DWORD cRangeLength = pVariables->cVariables;
1431
1432 while (cRangeLength)
1433 {
1434 // get variable in middle of range
1435 DWORD iPosition = cRangeLength / 2;
1436 BURN_VARIABLE* pVariable = &pVariables->rgVariables[iRangeFirst + iPosition];
1437
1438 switch (::CompareStringW(LOCALE_INVARIANT, SORT_STRINGSORT, wzVariable, -1, pVariable->sczName, -1))
1439 {
1440 case CSTR_LESS_THAN:
1441 // restrict range to elements before the current
1442 cRangeLength = iPosition;
1443 break;
1444 case CSTR_EQUAL:
1445 // variable found
1446 *piVariable = iRangeFirst + iPosition;
1447 ExitFunction1(hr = S_OK);
1448 case CSTR_GREATER_THAN:
1449 // restrict range to elements after the current
1450 iRangeFirst += iPosition + 1;
1451 cRangeLength -= iPosition + 1;
1452 break;
1453 default:
1454 ExitWithLastError(hr, "Failed to compare strings.");
1455 }
1456 }
1457
1458 *piVariable = iRangeFirst;
1459 hr = S_FALSE; // variable not found
1460
1461LExit:
1462 return hr;
1463}
1464
1465static HRESULT InsertVariable(
1466 __in BURN_VARIABLES* pVariables,
1467 __in_z LPCWSTR wzVariable,
1468 __in DWORD iPosition
1469 )
1470{
1471 HRESULT hr = S_OK;
1472 size_t cbAllocSize = 0;
1473
1474 // ensure there is room in the variable array
1475 if (pVariables->cVariables == pVariables->dwMaxVariables)
1476 {
1477 hr = ::DWordAdd(pVariables->dwMaxVariables, GROW_VARIABLE_ARRAY, &(pVariables->dwMaxVariables));
1478 ExitOnRootFailure(hr, "Overflow while growing variable array size");
1479
1480 if (pVariables->rgVariables)
1481 {
1482 hr = ::SizeTMult(sizeof(BURN_VARIABLE), pVariables->dwMaxVariables, &cbAllocSize);
1483 ExitOnRootFailure(hr, "Overflow while calculating size of variable array buffer");
1484
1485 LPVOID pv = MemReAlloc(pVariables->rgVariables, cbAllocSize, FALSE);
1486 ExitOnNull(pv, hr, E_OUTOFMEMORY, "Failed to allocate room for more variables.");
1487
1488 // Prefast claims it's possible to hit this. Putting the check in just in case.
1489 if (pVariables->dwMaxVariables < pVariables->cVariables)
1490 {
1491 hr = INTSAFE_E_ARITHMETIC_OVERFLOW;
1492 ExitOnRootFailure(hr, "Overflow while dealing with variable array buffer allocation");
1493 }
1494
1495 pVariables->rgVariables = (BURN_VARIABLE*)pv;
1496 memset(&pVariables->rgVariables[pVariables->cVariables], 0, sizeof(BURN_VARIABLE) * (pVariables->dwMaxVariables - pVariables->cVariables));
1497 }
1498 else
1499 {
1500 pVariables->rgVariables = (BURN_VARIABLE*)MemAlloc(sizeof(BURN_VARIABLE) * pVariables->dwMaxVariables, TRUE);
1501 ExitOnNull(pVariables->rgVariables, hr, E_OUTOFMEMORY, "Failed to allocate room for variables.");
1502 }
1503 }
1504
1505 // move variables
1506 if (0 < pVariables->cVariables - iPosition)
1507 {
1508 memmove(&pVariables->rgVariables[iPosition + 1], &pVariables->rgVariables[iPosition], sizeof(BURN_VARIABLE) * (pVariables->cVariables - iPosition));
1509 memset(&pVariables->rgVariables[iPosition], 0, sizeof(BURN_VARIABLE));
1510 }
1511
1512 ++pVariables->cVariables;
1513
1514 // allocate name
1515 hr = StrAllocString(&pVariables->rgVariables[iPosition].sczName, wzVariable, 0);
1516 ExitOnFailure(hr, "Failed to copy variable name.");
1517
1518LExit:
1519 return hr;
1520}
1521
1522static HRESULT SetVariableValue(
1523 __in BURN_VARIABLES* pVariables,
1524 __in_z LPCWSTR wzVariable,
1525 __in BURN_VARIANT* pVariant,
1526 __in SET_VARIABLE setBuiltin,
1527 __in BOOL fLog
1528 )
1529{
1530 HRESULT hr = S_OK;
1531 DWORD iVariable = 0;
1532
1533 ::EnterCriticalSection(&pVariables->csAccess);
1534
1535 hr = FindVariableIndexByName(pVariables, wzVariable, &iVariable);
1536 ExitOnFailure(hr, "Failed to find variable value '%ls'.", wzVariable);
1537
1538 // Insert element if not found.
1539 if (S_FALSE == hr)
1540 {
1541 hr = InsertVariable(pVariables, wzVariable, iVariable);
1542 ExitOnFailure(hr, "Failed to insert variable '%ls'.", wzVariable);
1543 }
1544 else if (BURN_VARIABLE_INTERNAL_TYPE_NORMAL < pVariables->rgVariables[iVariable].internalType) // built-in variables must be overridden.
1545 {
1546 if (SET_VARIABLE_OVERRIDE_BUILTIN == setBuiltin ||
1547 (SET_VARIABLE_OVERRIDE_PERSISTED_BUILTINS == setBuiltin && pVariables->rgVariables[iVariable].fPersisted) ||
1548 SET_VARIABLE_ANY == setBuiltin && BURN_VARIABLE_INTERNAL_TYPE_BUILTIN != pVariables->rgVariables[iVariable].internalType)
1549 {
1550 hr = S_OK;
1551 }
1552 else
1553 {
1554 hr = E_INVALIDARG;
1555 ExitOnRootFailure(hr, "Attempt to set built-in variable value: %ls", wzVariable);
1556 }
1557 }
1558 else // must *not* be a built-in variable so caller should not have tried to override it as a built-in.
1559 {
1560 // Not possible from external callers so just assert.
1561 AssertSz(SET_VARIABLE_OVERRIDE_BUILTIN != setBuiltin, "Intent to overwrite non-built-in variable.");
1562 }
1563
1564 // Log value when not overwriting a built-in variable.
1565 if (fLog && BURN_VARIABLE_INTERNAL_TYPE_NORMAL == pVariables->rgVariables[iVariable].internalType)
1566 {
1567 if (pVariables->rgVariables[iVariable].fHidden)
1568 {
1569 LogStringLine(REPORT_STANDARD, "Setting hidden variable '%ls'", wzVariable);
1570 }
1571 else
1572 {
1573 switch (pVariant->Type)
1574 {
1575 case BURN_VARIANT_TYPE_NONE:
1576 if (BURN_VARIANT_TYPE_NONE != pVariables->rgVariables[iVariable].Value.Type)
1577 {
1578 LogStringLine(REPORT_STANDARD, "Unsetting variable '%ls'", wzVariable);
1579 }
1580 break;
1581
1582 case BURN_VARIANT_TYPE_NUMERIC:
1583 LogStringLine(REPORT_STANDARD, "Setting numeric variable '%ls' to value %lld", wzVariable, pVariant->llValue);
1584 break;
1585
1586 case BURN_VARIANT_TYPE_FORMATTED: __fallthrough;
1587 case BURN_VARIANT_TYPE_STRING:
1588 if (!pVariant->sczValue)
1589 {
1590 LogStringLine(REPORT_STANDARD, "Unsetting variable '%ls'", wzVariable);
1591 }
1592 else
1593 {
1594 LogStringLine(REPORT_STANDARD, "Setting %ls variable '%ls' to value '%ls'", BURN_VARIANT_TYPE_FORMATTED == pVariant->Type ? L"formatted" : L"string", wzVariable, pVariant->sczValue);
1595 }
1596 break;
1597
1598 case BURN_VARIANT_TYPE_VERSION:
1599 if (!pVariant->pValue)
1600 {
1601 LogStringLine(REPORT_STANDARD, "Unsetting variable '%ls'", wzVariable);
1602 }
1603 else
1604 {
1605 LogStringLine(REPORT_STANDARD, "Setting version variable '%ls' to value '%ls'", wzVariable, pVariant->pValue->sczVersion);
1606 }
1607 break;
1608
1609 default:
1610 AssertSz(FALSE, "Unknown variant type.");
1611 break;
1612 }
1613 }
1614
1615 if (BURN_VARIANT_TYPE_VERSION == pVariant->Type && pVariant->pValue && pVariant->pValue->fInvalid)
1616 {
1617 LogId(REPORT_WARNING, MSG_VARIABLE_INVALID_VERSION, wzVariable);
1618 }
1619 }
1620
1621 // Update variable value.
1622 hr = BVariantSetValue(&pVariables->rgVariables[iVariable].Value, pVariant);
1623 ExitOnFailure(hr, "Failed to set value of variable: %ls", wzVariable);
1624
1625LExit:
1626 ::LeaveCriticalSection(&pVariables->csAccess);
1627
1628 if (FAILED(hr) && fLog)
1629 {
1630 LogStringLine(REPORT_STANDARD, "Setting variable failed: ID '%ls', HRESULT 0x%x", wzVariable, hr);
1631 }
1632
1633 return hr;
1634}
1635
1636static HRESULT InitializeVariableVersionNT(
1637 __in DWORD_PTR dwpData,
1638 __inout BURN_VARIANT* pValue
1639 )
1640{
1641 HRESULT hr = S_OK;
1642 RTL_OSVERSIONINFOEXW ovix = { };
1643 BURN_VARIANT value = { };
1644 VERUTIL_VERSION* pVersion = NULL;
1645
1646 hr = OsRtlGetVersion(&ovix);
1647 ExitOnFailure(hr, "Failed to get OS info.");
1648
1649 switch ((OS_INFO_VARIABLE)dwpData)
1650 {
1651 case OS_INFO_VARIABLE_ServicePackLevel:
1652 if (0 != ovix.wServicePackMajor)
1653 {
1654 value.llValue = static_cast<LONGLONG>(ovix.wServicePackMajor);
1655 value.Type = BURN_VARIANT_TYPE_NUMERIC;
1656 }
1657 break;
1658 case OS_INFO_VARIABLE_VersionNT:
1659 hr = VerVersionFromQword(MAKEQWORDVERSION(ovix.dwMajorVersion, ovix.dwMinorVersion, 0, 0), &pVersion);
1660 ExitOnFailure(hr, "Failed to create VersionNT from QWORD.");
1661
1662 value.pValue = pVersion;
1663 value.Type = BURN_VARIANT_TYPE_VERSION;
1664 break;
1665 case OS_INFO_VARIABLE_VersionNT64:
1666 {
1667#if !defined(_WIN64)
1668 BOOL fIsWow64 = FALSE;
1669
1670 ProcWow64(::GetCurrentProcess(), &fIsWow64);
1671 if (fIsWow64)
1672#endif
1673 {
1674 hr = VerVersionFromQword(MAKEQWORDVERSION(ovix.dwMajorVersion, ovix.dwMinorVersion, 0, 0), &pVersion);
1675 ExitOnFailure(hr, "Failed to create VersionNT64 from QWORD.");
1676
1677 value.pValue = pVersion;
1678 value.Type = BURN_VARIANT_TYPE_VERSION;
1679 }
1680 }
1681 break;
1682 case OS_INFO_VARIABLE_WindowsBuildNumber:
1683 value.llValue = static_cast<LONGLONG>(ovix.dwBuildNumber);
1684 value.Type = BURN_VARIANT_TYPE_NUMERIC;
1685 default:
1686 AssertSz(FALSE, "Unknown OS info type.");
1687 break;
1688 }
1689
1690 hr = BVariantCopy(&value, pValue);
1691 ExitOnFailure(hr, "Failed to set variant value.");
1692
1693LExit:
1694 ReleaseVerutilVersion(pVersion);
1695
1696 return hr;
1697}
1698
1699static HRESULT InitializeVariableOsInfo(
1700 __in DWORD_PTR dwpData,
1701 __inout BURN_VARIANT* pValue
1702 )
1703{
1704 HRESULT hr = S_OK;
1705 RTL_OSVERSIONINFOEXW ovix = { };
1706 BURN_VARIANT value = { };
1707
1708 hr = OsRtlGetVersion(&ovix);
1709 ExitOnFailure(hr, "Failed to get OS info.");
1710
1711 switch ((OS_INFO_VARIABLE)dwpData)
1712 {
1713 case OS_INFO_VARIABLE_NTProductType:
1714 value.llValue = ovix.wProductType;
1715 value.Type = BURN_VARIANT_TYPE_NUMERIC;
1716 break;
1717 case OS_INFO_VARIABLE_NTSuiteBackOffice:
1718 value.llValue = VER_SUITE_BACKOFFICE & ovix.wSuiteMask ? 1 : 0;
1719 value.Type = BURN_VARIANT_TYPE_NUMERIC;
1720 break;
1721 case OS_INFO_VARIABLE_NTSuiteDataCenter:
1722 value.llValue = VER_SUITE_DATACENTER & ovix.wSuiteMask ? 1 : 0;
1723 value.Type = BURN_VARIANT_TYPE_NUMERIC;
1724 break;
1725 case OS_INFO_VARIABLE_NTSuiteEnterprise:
1726 value.llValue = VER_SUITE_ENTERPRISE & ovix.wSuiteMask ? 1 : 0;
1727 value.Type = BURN_VARIANT_TYPE_NUMERIC;
1728 break;
1729 case OS_INFO_VARIABLE_NTSuitePersonal:
1730 value.llValue = VER_SUITE_PERSONAL & ovix.wSuiteMask ? 1 : 0;
1731 value.Type = BURN_VARIANT_TYPE_NUMERIC;
1732 break;
1733 case OS_INFO_VARIABLE_NTSuiteSmallBusiness:
1734 value.llValue = VER_SUITE_SMALLBUSINESS & ovix.wSuiteMask ? 1 : 0;
1735 value.Type = BURN_VARIANT_TYPE_NUMERIC;
1736 break;
1737 case OS_INFO_VARIABLE_NTSuiteSmallBusinessRestricted:
1738 value.llValue = VER_SUITE_SMALLBUSINESS_RESTRICTED & ovix.wSuiteMask ? 1 : 0;
1739 value.Type = BURN_VARIANT_TYPE_NUMERIC;
1740 break;
1741 case OS_INFO_VARIABLE_NTSuiteWebServer:
1742 value.llValue = VER_SUITE_BLADE & ovix.wSuiteMask ? 1 : 0;
1743 value.Type = BURN_VARIANT_TYPE_NUMERIC;
1744 break;
1745 case OS_INFO_VARIABLE_CompatibilityMode:
1746 {
1747 DWORDLONG dwlConditionMask = 0;
1748 VER_SET_CONDITION(dwlConditionMask, VER_MAJORVERSION, VER_EQUAL);
1749 VER_SET_CONDITION(dwlConditionMask, VER_MINORVERSION, VER_EQUAL);
1750 VER_SET_CONDITION(dwlConditionMask, VER_SERVICEPACKMAJOR, VER_EQUAL);
1751 VER_SET_CONDITION(dwlConditionMask, VER_SERVICEPACKMINOR, VER_EQUAL);
1752
1753 value.llValue = ::VerifyVersionInfoW(&ovix, VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR, dwlConditionMask);
1754 value.Type = BURN_VARIANT_TYPE_NUMERIC;
1755 }
1756 break;
1757 case OS_INFO_VARIABLE_TerminalServer:
1758 value.llValue = (VER_SUITE_TERMINAL == (ovix.wSuiteMask & VER_SUITE_TERMINAL)) && (VER_SUITE_SINGLEUSERTS != (ovix.wSuiteMask & VER_SUITE_SINGLEUSERTS)) ? 1 : 0;
1759 value.Type = BURN_VARIANT_TYPE_NUMERIC;
1760 break;
1761 default:
1762 AssertSz(FALSE, "Unknown OS info type.");
1763 break;
1764 }
1765
1766 hr = BVariantCopy(&value, pValue);
1767 ExitOnFailure(hr, "Failed to set variant value.");
1768
1769LExit:
1770 return hr;
1771}
1772
1773static HRESULT InitializeVariableSystemInfo(
1774 __in DWORD_PTR dwpData,
1775 __inout BURN_VARIANT* pValue
1776 )
1777{
1778 HRESULT hr = S_OK;
1779 SYSTEM_INFO si = { };
1780 BURN_VARIANT value = { };
1781
1782 ::GetNativeSystemInfo(&si);
1783
1784 switch ((OS_INFO_VARIABLE)dwpData)
1785 {
1786 case OS_INFO_VARIABLE_ProcessorArchitecture:
1787 value.llValue = si.wProcessorArchitecture;
1788 value.Type = BURN_VARIANT_TYPE_NUMERIC;
1789 break;
1790 default:
1791 AssertSz(FALSE, "Unknown OS info type.");
1792 break;
1793 }
1794
1795 hr = BVariantCopy(&value, pValue);
1796 ExitOnFailure(hr, "Failed to set variant value.");
1797
1798LExit:
1799 return hr;
1800}
1801
1802static HRESULT InitializeVariableComputerName(
1803 __in DWORD_PTR dwpData,
1804 __inout BURN_VARIANT* pValue
1805 )
1806{
1807 UNREFERENCED_PARAMETER(dwpData);
1808
1809 HRESULT hr = S_OK;
1810 WCHAR wzComputerName[MAX_COMPUTERNAME_LENGTH + 1] = { };
1811 DWORD cchComputerName = countof(wzComputerName);
1812
1813 // get computer name
1814 if (!::GetComputerNameW(wzComputerName, &cchComputerName))
1815 {
1816 ExitWithLastError(hr, "Failed to get computer name.");
1817 }
1818
1819 // set value
1820 hr = BVariantSetString(pValue, wzComputerName, 0, FALSE);
1821 ExitOnFailure(hr, "Failed to set variant value.");
1822
1823LExit:
1824 return hr;
1825}
1826
1827static HRESULT InitializeVariableVersionMsi(
1828 __in DWORD_PTR /*dwpData*/,
1829 __inout BURN_VARIANT* pValue
1830 )
1831{
1832 HRESULT hr = S_OK;
1833 DLLGETVERSIONPROC pfnMsiDllGetVersion = NULL;
1834 DLLVERSIONINFO msiVersionInfo = { };
1835 VERUTIL_VERSION* pVersion = NULL;
1836
1837 // get DllGetVersion proc address
1838 pfnMsiDllGetVersion = (DLLGETVERSIONPROC)::GetProcAddress(::GetModuleHandleW(L"msi"), "DllGetVersion");
1839 ExitOnNullWithLastError(pfnMsiDllGetVersion, hr, "Failed to find DllGetVersion entry point in msi.dll.");
1840
1841 // get msi.dll version info
1842 msiVersionInfo.cbSize = sizeof(DLLVERSIONINFO);
1843 hr = pfnMsiDllGetVersion(&msiVersionInfo);
1844 ExitOnFailure(hr, "Failed to get msi.dll version info.");
1845
1846 hr = VerVersionFromQword(MAKEQWORDVERSION(msiVersionInfo.dwMajorVersion, msiVersionInfo.dwMinorVersion, 0, 0), &pVersion);
1847 ExitOnFailure(hr, "Failed to create msi.dll version from QWORD.");
1848
1849 hr = BVariantSetVersion(pValue, pVersion);
1850 ExitOnFailure(hr, "Failed to set variant value.");
1851
1852LExit:
1853 ReleaseVerutilVersion(pVersion);
1854
1855 return hr;
1856}
1857
1858static HRESULT InitializeVariableCsidlFolder(
1859 __in DWORD_PTR dwpData,
1860 __inout BURN_VARIANT* pValue
1861 )
1862{
1863 HRESULT hr = S_OK;
1864 LPWSTR sczPath = NULL;
1865 int nFolder = (int)dwpData;
1866
1867 // get folder path
1868 hr = ShelGetFolder(&sczPath, nFolder);
1869 ExitOnRootFailure(hr, "Failed to get shell folder.");
1870
1871 // set value
1872 hr = BVariantSetString(pValue, sczPath, 0, FALSE);
1873 ExitOnFailure(hr, "Failed to set variant value.");
1874
1875LExit:
1876 ReleaseStr(sczPath);
1877
1878 return hr;
1879}
1880
1881static HRESULT InitializeVariableTempFolder(
1882 __in DWORD_PTR dwpData,
1883 __inout BURN_VARIANT* pValue
1884 )
1885{
1886 UNREFERENCED_PARAMETER(dwpData);
1887
1888 HRESULT hr = S_OK;
1889 WCHAR wzPath[MAX_PATH] = { };
1890
1891 // get volume path name
1892 if (!::GetTempPathW(MAX_PATH, wzPath))
1893 {
1894 ExitWithLastError(hr, "Failed to get temp path.");
1895 }
1896
1897 // set value
1898 hr = BVariantSetString(pValue, wzPath, 0, FALSE);
1899 ExitOnFailure(hr, "Failed to set variant value.");
1900
1901LExit:
1902 return hr;
1903}
1904
1905static HRESULT InitializeVariableSystemFolder(
1906 __in DWORD_PTR dwpData,
1907 __inout BURN_VARIANT* pValue
1908 )
1909{
1910 HRESULT hr = S_OK;
1911 BOOL f64 = (BOOL)dwpData;
1912 WCHAR wzSystemFolder[MAX_PATH] = { };
1913
1914#if !defined(_WIN64)
1915 BOOL fIsWow64 = FALSE;
1916 ProcWow64(::GetCurrentProcess(), &fIsWow64);
1917
1918 if (fIsWow64)
1919 {
1920 if (f64)
1921 {
1922 if (!::GetSystemDirectoryW(wzSystemFolder, countof(wzSystemFolder)))
1923 {
1924 ExitWithLastError(hr, "Failed to get 64-bit system folder.");
1925 }
1926 }
1927 else
1928 {
1929 if (!::GetSystemWow64DirectoryW(wzSystemFolder, countof(wzSystemFolder)))
1930 {
1931 ExitWithLastError(hr, "Failed to get 32-bit system folder.");
1932 }
1933 }
1934 }
1935 else
1936 {
1937 if (!f64)
1938 {
1939 if (!::GetSystemDirectoryW(wzSystemFolder, countof(wzSystemFolder)))
1940 {
1941 ExitWithLastError(hr, "Failed to get 32-bit system folder.");
1942 }
1943 }
1944 }
1945#else
1946 if (f64)
1947 {
1948 if (!::GetSystemDirectoryW(wzSystemFolder, countof(wzSystemFolder)))
1949 {
1950 ExitWithLastError(hr, "Failed to get 64-bit system folder.");
1951 }
1952 }
1953 else
1954 {
1955 if (!::GetSystemWow64DirectoryW(wzSystemFolder, countof(wzSystemFolder)))
1956 {
1957 ExitWithLastError(hr, "Failed to get 32-bit system folder.");
1958 }
1959 }
1960#endif
1961
1962 if (*wzSystemFolder)
1963 {
1964 hr = PathFixedBackslashTerminate(wzSystemFolder, countof(wzSystemFolder));
1965 ExitOnFailure(hr, "Failed to backslash terminate system folder.");
1966 }
1967
1968 // set value
1969 hr = BVariantSetString(pValue, wzSystemFolder, 0, FALSE);
1970 ExitOnFailure(hr, "Failed to set system folder variant value.");
1971
1972LExit:
1973 return hr;
1974}
1975
1976static HRESULT InitializeVariableWindowsVolumeFolder(
1977 __in DWORD_PTR dwpData,
1978 __inout BURN_VARIANT* pValue
1979 )
1980{
1981 UNREFERENCED_PARAMETER(dwpData);
1982
1983 HRESULT hr = S_OK;
1984 WCHAR wzWindowsPath[MAX_PATH] = { };
1985 WCHAR wzVolumePath[MAX_PATH] = { };
1986
1987 // get windows directory
1988 if (!::GetWindowsDirectoryW(wzWindowsPath, countof(wzWindowsPath)))
1989 {
1990 ExitWithLastError(hr, "Failed to get windows directory.");
1991 }
1992
1993 // get volume path name
1994 if (!::GetVolumePathNameW(wzWindowsPath, wzVolumePath, MAX_PATH))
1995 {
1996 ExitWithLastError(hr, "Failed to get volume path name.");
1997 }
1998
1999 // set value
2000 hr = BVariantSetString(pValue, wzVolumePath, 0, FALSE);
2001 ExitOnFailure(hr, "Failed to set variant value.");
2002
2003LExit:
2004 return hr;
2005}
2006
2007static HRESULT InitializeVariablePrivileged(
2008 __in DWORD_PTR dwpData,
2009 __inout BURN_VARIANT* pValue
2010 )
2011{
2012 UNREFERENCED_PARAMETER(dwpData);
2013
2014 HRESULT hr = S_OK;
2015 BOOL fPrivileged = FALSE;
2016
2017 // check if process could run privileged.
2018 hr = OsCouldRunPrivileged(&fPrivileged);
2019 ExitOnFailure(hr, "Failed to check if process could run privileged.");
2020
2021 // set value
2022 hr = BVariantSetNumeric(pValue, fPrivileged);
2023 ExitOnFailure(hr, "Failed to set variant value.");
2024
2025LExit:
2026 return hr;
2027}
2028
2029static HRESULT InitializeSystemLanguageID(
2030 __in DWORD_PTR dwpData,
2031 __inout BURN_VARIANT* pValue
2032 )
2033{
2034 UNREFERENCED_PARAMETER(dwpData);
2035
2036 HRESULT hr = S_OK;
2037 LANGID langid = ::GetSystemDefaultLangID();
2038
2039 hr = BVariantSetNumeric(pValue, langid);
2040 ExitOnFailure(hr, "Failed to set variant value.");
2041
2042LExit:
2043 return hr;
2044}
2045
2046static HRESULT InitializeUserUILanguageID(
2047 __in DWORD_PTR dwpData,
2048 __inout BURN_VARIANT* pValue
2049 )
2050{
2051 UNREFERENCED_PARAMETER(dwpData);
2052
2053 HRESULT hr = S_OK;
2054 LANGID langid = ::GetUserDefaultUILanguage();
2055
2056 hr = BVariantSetNumeric(pValue, langid);
2057 ExitOnFailure(hr, "Failed to set variant value.");
2058
2059LExit:
2060 return hr;
2061}
2062
2063static HRESULT InitializeUserLanguageID(
2064 __in DWORD_PTR dwpData,
2065 __inout BURN_VARIANT* pValue
2066 )
2067{
2068 UNREFERENCED_PARAMETER(dwpData);
2069
2070 HRESULT hr = S_OK;
2071 LANGID langid = ::GetUserDefaultLangID();
2072
2073 hr = BVariantSetNumeric(pValue, langid);
2074 ExitOnFailure(hr, "Failed to set variant value.");
2075
2076LExit:
2077 return hr;
2078}
2079
2080static HRESULT InitializeVariableString(
2081 __in DWORD_PTR dwpData,
2082 __inout BURN_VARIANT* pValue
2083 )
2084{
2085 HRESULT hr = S_OK;
2086 LPCWSTR wzValue = (LPCWSTR)dwpData;
2087
2088 // set value
2089 hr = BVariantSetString(pValue, wzValue, 0, FALSE);
2090 ExitOnFailure(hr, "Failed to set variant value.");
2091
2092LExit:
2093 return hr;
2094}
2095
2096static HRESULT InitializeVariableNumeric(
2097 __in DWORD_PTR dwpData,
2098 __inout BURN_VARIANT* pValue
2099 )
2100{
2101 HRESULT hr = S_OK;
2102 LONGLONG llValue = (LONGLONG)dwpData;
2103
2104 // set value
2105 hr = BVariantSetNumeric(pValue, llValue);
2106 ExitOnFailure(hr, "Failed to set variant value.");
2107
2108LExit:
2109 return hr;
2110}
2111
2112#if !defined(_WIN64)
2113static HRESULT InitializeVariableRegistryFolder(
2114 __in DWORD_PTR dwpData,
2115 __inout BURN_VARIANT* pValue
2116 )
2117{
2118 HRESULT hr = S_OK;
2119 int nFolder = (int)dwpData;
2120 LPWSTR sczPath = NULL;
2121
2122 BOOL fIsWow64 = FALSE;
2123
2124 ProcWow64(::GetCurrentProcess(), &fIsWow64);
2125 if (!fIsWow64) // on 32-bit machines, variables aren't set
2126 {
2127 ExitFunction();
2128 }
2129
2130 hr = Get64bitFolderFromRegistry(nFolder, &sczPath);
2131 ExitOnFailure(hr, "Failed to get 64-bit folder.");
2132
2133 // set value
2134 hr = BVariantSetString(pValue, sczPath, 0, FALSE);
2135 ExitOnFailure(hr, "Failed to set variant value.");
2136
2137LExit:
2138 ReleaseStr(sczPath);
2139
2140 return hr;
2141}
2142#endif
2143
2144static HRESULT InitializeVariable6432Folder(
2145 __in DWORD_PTR dwpData,
2146 __inout BURN_VARIANT* pValue
2147 )
2148{
2149 HRESULT hr = S_OK;
2150 int nFolder = (int)dwpData;
2151 LPWSTR sczPath = NULL;
2152
2153#if !defined(_WIN64)
2154 BOOL fIsWow64 = FALSE;
2155
2156 // If 32-bit use shell-folder.
2157 ProcWow64(::GetCurrentProcess(), &fIsWow64);
2158 if (!fIsWow64)
2159 {
2160 hr = ShelGetFolder(&sczPath, nFolder);
2161 ExitOnRootFailure(hr, "Failed to get shell folder.");
2162 }
2163 else
2164#endif
2165 {
2166 hr = Get64bitFolderFromRegistry(nFolder, &sczPath);
2167 ExitOnFailure(hr, "Failed to get 64-bit folder.");
2168 }
2169
2170 // set value
2171 hr = BVariantSetString(pValue, sczPath, 0, FALSE);
2172 ExitOnFailure(hr, "Failed to set variant value.");
2173
2174LExit:
2175 ReleaseStr(sczPath);
2176
2177 return hr;
2178}
2179
2180// Get the date in the same format as Windows Installer.
2181static HRESULT InitializeVariableDate(
2182 __in DWORD_PTR /*dwpData*/,
2183 __inout BURN_VARIANT* pValue
2184 )
2185{
2186 HRESULT hr = S_OK;
2187 SYSTEMTIME systime = { };
2188 LPWSTR sczDate = NULL;
2189 int cchDate = 0;
2190
2191 ::GetSystemTime(&systime);
2192
2193 cchDate = ::GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &systime, NULL, NULL, cchDate);
2194 if (!cchDate)
2195 {
2196 ExitOnLastError(hr, "Failed to get the required buffer length for the Date.");
2197 }
2198
2199 hr = StrAlloc(&sczDate, cchDate);
2200 ExitOnFailure(hr, "Failed to allocate the buffer for the Date.");
2201
2202 if (!::GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &systime, NULL, sczDate, cchDate))
2203 {
2204 ExitOnLastError(hr, "Failed to get the Date.");
2205 }
2206
2207 // set value
2208 hr = BVariantSetString(pValue, sczDate, cchDate, FALSE);
2209 ExitOnFailure(hr, "Failed to set variant value.");
2210
2211LExit:
2212 ReleaseStr(sczDate);
2213
2214 return hr;
2215}
2216
2217static HRESULT InitializeVariableInstallerName(
2218 __in DWORD_PTR /*dwpData*/,
2219 __inout BURN_VARIANT* pValue
2220 )
2221{
2222 HRESULT hr = S_OK;
2223
2224 // set value
2225 hr = BVariantSetString(pValue, L"WiX Burn", 0, FALSE);
2226 ExitOnFailure(hr, "Failed to set variant value.");
2227
2228LExit:
2229 return hr;
2230}
2231
2232static HRESULT InitializeVariableInstallerVersion(
2233 __in DWORD_PTR /*dwpData*/,
2234 __inout BURN_VARIANT* pValue
2235 )
2236{
2237 HRESULT hr = S_OK;
2238 LPWSTR sczVersion = NULL;
2239
2240 hr = StrAllocStringAnsi(&sczVersion, szVerMajorMinorBuild, 0, CP_ACP);
2241 ExitOnFailure(hr, "Failed to copy the engine version.");
2242
2243 // set value
2244 hr = BVariantSetString(pValue, sczVersion, 0, FALSE);
2245 ExitOnFailure(hr, "Failed to set variant value.");
2246
2247LExit:
2248 ReleaseStr(sczVersion);
2249
2250 return hr;
2251}
2252
2253static HRESULT InitializeVariableVersion(
2254 __in DWORD_PTR dwpData,
2255 __inout BURN_VARIANT* pValue
2256 )
2257{
2258 HRESULT hr = S_OK;
2259 LPCWSTR wzValue = (LPCWSTR)dwpData;
2260 VERUTIL_VERSION* pVersion = NULL;
2261
2262 hr = VerParseVersion(wzValue, 0, FALSE, &pVersion);
2263 ExitOnFailure(hr, "Failed to initialize version.");
2264
2265 // set value
2266 hr = BVariantSetVersion(pValue, pVersion);
2267 ExitOnFailure(hr, "Failed to set variant value.");
2268
2269LExit:
2270 ReleaseVerutilVersion(pVersion);
2271
2272 return hr;
2273}
2274
2275// Get the current user the same as Windows Installer.
2276static HRESULT InitializeVariableLogonUser(
2277 __in DWORD_PTR /*dwpData*/,
2278 __inout BURN_VARIANT* pValue
2279 )
2280{
2281 HRESULT hr = S_OK;
2282 WCHAR wzUserName[UNLEN + 1];
2283 DWORD cchUserName = countof(wzUserName);
2284
2285 if (!::GetUserNameW(wzUserName, &cchUserName))
2286 {
2287 ExitOnLastError(hr, "Failed to get the user name.");
2288 }
2289
2290 // set value
2291 hr = BVariantSetString(pValue, wzUserName, 0, FALSE);
2292 ExitOnFailure(hr, "Failed to set variant value.");
2293
2294LExit:
2295 return hr;
2296}
2297
2298static HRESULT Get64bitFolderFromRegistry(
2299 __in int nFolder,
2300 __deref_out_z LPWSTR* psczPath
2301 )
2302{
2303 HRESULT hr = S_OK;
2304 HKEY hkFolders = NULL;
2305
2306 AssertSz(CSIDL_PROGRAM_FILES == nFolder || CSIDL_PROGRAM_FILES_COMMON == nFolder, "Unknown folder CSIDL.");
2307 LPCWSTR wzFolderValue = CSIDL_PROGRAM_FILES_COMMON == nFolder ? L"CommonFilesDir" : L"ProgramFilesDir";
2308
2309 hr = RegOpen(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion", KEY_READ | KEY_WOW64_64KEY, &hkFolders);
2310 ExitOnFailure(hr, "Failed to open Windows folder key.");
2311
2312 hr = RegReadString(hkFolders, wzFolderValue, psczPath);
2313 ExitOnFailure(hr, "Failed to read folder path for '%ls'.", wzFolderValue);
2314
2315 hr = PathBackslashTerminate(psczPath);
2316 ExitOnFailure(hr, "Failed to ensure path was backslash terminated.");
2317
2318LExit:
2319 ReleaseRegKey(hkFolders);
2320
2321 return hr;
2322}
2323