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