aboutsummaryrefslogtreecommitdiff
path: root/src/balutil/balutil.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/balutil/balutil.cpp382
1 files changed, 382 insertions, 0 deletions
diff --git a/src/balutil/balutil.cpp b/src/balutil/balutil.cpp
new file mode 100644
index 00000000..df254359
--- /dev/null
+++ b/src/balutil/balutil.cpp
@@ -0,0 +1,382 @@
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
5const DWORD VARIABLE_GROW_FACTOR = 80;
6static IBootstrapperEngine* vpEngine = NULL;
7
8// prototypes
9
10DAPI_(void) BalInitialize(
11 __in IBootstrapperEngine* pEngine
12 )
13{
14 pEngine->AddRef();
15
16 ReleaseObject(vpEngine);
17 vpEngine = pEngine;
18}
19
20DAPI_(HRESULT) BalInitializeFromCreateArgs(
21 __in const BOOTSTRAPPER_CREATE_ARGS* pArgs,
22 __out_opt IBootstrapperEngine** ppEngine
23 )
24{
25 HRESULT hr = S_OK;
26 IBootstrapperEngine* pEngine = NULL;
27
28 hr = BalBootstrapperEngineCreate(pArgs->pfnBootstrapperEngineProc, pArgs->pvBootstrapperEngineProcContext, &pEngine);
29 ExitOnFailure(hr, "Failed to create BalBootstrapperEngine.");
30
31 BalInitialize(pEngine);
32
33 if (ppEngine)
34 {
35 *ppEngine = pEngine;
36 }
37 pEngine = NULL;
38
39LExit:
40 ReleaseObject(pEngine);
41
42 return hr;
43}
44
45
46DAPI_(void) BalUninitialize()
47{
48 ReleaseNullObject(vpEngine);
49}
50
51
52DAPI_(HRESULT) BalManifestLoad(
53 __in HMODULE hBootstrapperApplicationModule,
54 __out IXMLDOMDocument** ppixdManifest
55 )
56{
57 HRESULT hr = S_OK;
58 LPWSTR sczPath = NULL;
59
60 hr = PathRelativeToModule(&sczPath, BAL_MANIFEST_FILENAME, hBootstrapperApplicationModule);
61 ExitOnFailure(hr, "Failed to get path to bootstrapper application manifest: %ls", BAL_MANIFEST_FILENAME);
62
63 hr = XmlLoadDocumentFromFile(sczPath, ppixdManifest);
64 ExitOnFailure(hr, "Failed to load bootstrapper application manifest '%ls' from path: %ls", BAL_MANIFEST_FILENAME, sczPath);
65
66LExit:
67 ReleaseStr(sczPath);
68 return hr;
69}
70
71
72DAPI_(HRESULT) BalEvaluateCondition(
73 __in_z LPCWSTR wzCondition,
74 __out BOOL* pf
75 )
76{
77 HRESULT hr = S_OK;
78
79 if (!vpEngine)
80 {
81 hr = E_POINTER;
82 ExitOnRootFailure(hr, "BalInitialize() must be called first.");
83 }
84
85 hr = vpEngine->EvaluateCondition(wzCondition, pf);
86
87LExit:
88 return hr;
89}
90
91
92// The contents of psczOut may be sensitive, should keep encrypted and SecureZeroFree.
93DAPI_(HRESULT) BalFormatString(
94 __in_z LPCWSTR wzFormat,
95 __inout LPWSTR* psczOut
96 )
97{
98 HRESULT hr = S_OK;
99 DWORD cch = 0;
100
101 if (!vpEngine)
102 {
103 hr = E_POINTER;
104 ExitOnRootFailure(hr, "BalInitialize() must be called first.");
105 }
106
107 if (*psczOut)
108 {
109 hr = StrMaxLength(*psczOut, reinterpret_cast<DWORD_PTR*>(&cch));
110 ExitOnFailure(hr, "Failed to determine length of value.");
111 }
112
113 hr = vpEngine->FormatString(wzFormat, *psczOut, &cch);
114 if (E_MOREDATA == hr)
115 {
116 ++cch;
117
118 hr = StrAllocSecure(psczOut, cch);
119 ExitOnFailure(hr, "Failed to allocate value.");
120
121 hr = vpEngine->FormatString(wzFormat, *psczOut, &cch);
122 }
123
124LExit:
125 return hr;
126}
127
128
129// The contents of pllValue may be sensitive, if variable is hidden should keep value encrypted and SecureZeroMemory.
130DAPI_(HRESULT) BalGetNumericVariable(
131 __in_z LPCWSTR wzVariable,
132 __out LONGLONG* pllValue
133 )
134{
135 HRESULT hr = S_OK;
136
137 if (!vpEngine)
138 {
139 hr = E_POINTER;
140 ExitOnRootFailure(hr, "BalInitialize() must be called first.");
141 }
142
143 hr = vpEngine->GetVariableNumeric(wzVariable, pllValue);
144
145LExit:
146 return hr;
147}
148
149
150DAPI_(HRESULT) BalSetNumericVariable(
151 __in_z LPCWSTR wzVariable,
152 __in LONGLONG llValue
153 )
154{
155 HRESULT hr = S_OK;
156
157 if (!vpEngine)
158 {
159 hr = E_POINTER;
160 ExitOnRootFailure(hr, "BalInitialize() must be called first.");
161 }
162
163 hr = vpEngine->SetVariableNumeric(wzVariable, llValue);
164
165LExit:
166 return hr;
167}
168
169
170DAPI_(BOOL) BalStringVariableExists(
171 __in_z LPCWSTR wzVariable
172 )
173{
174 HRESULT hr = S_OK;
175 DWORD cch = 0;
176
177 if (!vpEngine)
178 {
179 hr = E_POINTER;
180 ExitOnRootFailure(hr, "BalInitialize() must be called first.");
181 }
182
183 hr = vpEngine->GetVariableString(wzVariable, NULL, &cch);
184
185LExit:
186 return E_MOREDATA == hr; // string exists only if there are more than zero characters in the variable.
187}
188
189
190// The contents of psczValue may be sensitive, if variable is hidden should keep value encrypted and SecureZeroFree.
191DAPI_(HRESULT) BalGetStringVariable(
192 __in_z LPCWSTR wzVariable,
193 __inout LPWSTR* psczValue
194 )
195{
196 HRESULT hr = S_OK;
197 DWORD cch = 0;
198
199 if (!vpEngine)
200 {
201 hr = E_POINTER;
202 ExitOnRootFailure(hr, "BalInitialize() must be called first.");
203 }
204
205 if (*psczValue)
206 {
207 hr = StrMaxLength(*psczValue, reinterpret_cast<DWORD_PTR*>(&cch));
208 ExitOnFailure(hr, "Failed to determine length of value.");
209 }
210
211 hr = vpEngine->GetVariableString(wzVariable, *psczValue, &cch);
212 if (E_MOREDATA == hr)
213 {
214 ++cch;
215
216 hr = StrAllocSecure(psczValue, cch);
217 ExitOnFailure(hr, "Failed to allocate value.");
218
219 hr = vpEngine->GetVariableString(wzVariable, *psczValue, &cch);
220 }
221
222LExit:
223 return hr;
224}
225
226DAPI_(HRESULT) BalSetStringVariable(
227 __in_z LPCWSTR wzVariable,
228 __in_z_opt LPCWSTR wzValue
229 )
230{
231 HRESULT hr = S_OK;
232
233 if (!vpEngine)
234 {
235 hr = E_POINTER;
236 ExitOnRootFailure(hr, "BalInitialize() must be called first.");
237 }
238
239 hr = vpEngine->SetVariableString(wzVariable, wzValue);
240
241LExit:
242 return hr;
243}
244
245
246DAPIV_(HRESULT) BalLog(
247 __in BOOTSTRAPPER_LOG_LEVEL level,
248 __in_z __format_string LPCSTR szFormat,
249 ...
250 )
251{
252 HRESULT hr = S_OK;
253 va_list args;
254 LPSTR sczFormattedAnsi = NULL;
255 LPWSTR sczMessage = NULL;
256
257 if (!vpEngine)
258 {
259 hr = E_POINTER;
260 ExitOnRootFailure(hr, "BalInitialize() must be called first.");
261 }
262
263 va_start(args, szFormat);
264 hr = StrAnsiAllocFormattedArgs(&sczFormattedAnsi, szFormat, args);
265 va_end(args);
266 ExitOnFailure(hr, "Failed to format log string.");
267
268 hr = StrAllocStringAnsi(&sczMessage, sczFormattedAnsi, 0, CP_UTF8);
269 ExitOnFailure(hr, "Failed to convert log string to Unicode.");
270
271 hr = vpEngine->Log(level, sczMessage);
272
273LExit:
274 ReleaseStr(sczMessage);
275 ReleaseStr(sczFormattedAnsi);
276 return hr;
277}
278
279
280DAPIV_(HRESULT) BalLogError(
281 __in HRESULT hrError,
282 __in_z __format_string LPCSTR szFormat,
283 ...
284 )
285{
286 HRESULT hr = S_OK;
287 va_list args;
288 LPSTR sczFormattedAnsi = NULL;
289 LPWSTR sczMessage = NULL;
290
291 if (!vpEngine)
292 {
293 hr = E_POINTER;
294 ExitOnRootFailure(hr, "BalInitialize() must be called first.");
295 }
296
297 va_start(args, szFormat);
298 hr = StrAnsiAllocFormattedArgs(&sczFormattedAnsi, szFormat, args);
299 va_end(args);
300 ExitOnFailure(hr, "Failed to format error log string.");
301
302 hr = StrAllocFormatted(&sczMessage, L"Error 0x%08x: %S", hrError, sczFormattedAnsi);
303 ExitOnFailure(hr, "Failed to prepend error number to error log string.");
304
305 hr = vpEngine->Log(BOOTSTRAPPER_LOG_LEVEL_ERROR, sczMessage);
306
307LExit:
308 ReleaseStr(sczMessage);
309 ReleaseStr(sczFormattedAnsi);
310 return hr;
311}
312
313DAPIV_(HRESULT) BalLogId(
314 __in BOOTSTRAPPER_LOG_LEVEL level,
315 __in DWORD dwLogId,
316 __in HMODULE hModule,
317 ...
318 )
319{
320 HRESULT hr = S_OK;
321 va_list args;
322
323 if (!vpEngine)
324 {
325 hr = E_POINTER;
326 ExitOnRootFailure(hr, "BalInitialize() must be called first.");
327 }
328
329 va_start(args, hModule);
330 hr = BalLogIdArgs(level, dwLogId, hModule, args);
331 va_end(args);
332
333LExit:
334 return hr;
335}
336
337DAPI_(HRESULT) BalLogIdArgs(
338 __in BOOTSTRAPPER_LOG_LEVEL level,
339 __in DWORD dwLogId,
340 __in HMODULE hModule,
341 __in va_list args
342 )
343{
344
345 HRESULT hr = S_OK;
346 LPWSTR pwz = NULL;
347 DWORD cch = 0;
348
349 if (!vpEngine)
350 {
351 hr = E_POINTER;
352 ExitOnRootFailure(hr, "BalInitialize() must be called first.");
353 }
354
355 // Get the string for the id.
356#pragma prefast(push)
357#pragma prefast(disable:25028)
358#pragma prefast(disable:25068)
359 cch = ::FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_HMODULE,
360 static_cast<LPCVOID>(hModule), dwLogId, 0, reinterpret_cast<LPWSTR>(&pwz), 0, &args);
361#pragma prefast(pop)
362
363 if (0 == cch)
364 {
365 ExitOnLastError(hr, "Failed to log id: %d", dwLogId);
366 }
367
368 if (2 <= cch && L'\r' == pwz[cch - 2] && L'\n' == pwz[cch - 1])
369 {
370 pwz[cch - 2] = L'\0'; // remove newline from message table.
371 }
372
373 hr = vpEngine->Log(level, pwz);
374
375LExit:
376 if (pwz)
377 {
378 ::LocalFree(pwz);
379 }
380
381 return hr;
382}