diff options
Diffstat (limited to '')
-rw-r--r-- | src/balutil/balutil.cpp | 382 |
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 | |||
5 | const DWORD VARIABLE_GROW_FACTOR = 80; | ||
6 | static IBootstrapperEngine* vpEngine = NULL; | ||
7 | |||
8 | // prototypes | ||
9 | |||
10 | DAPI_(void) BalInitialize( | ||
11 | __in IBootstrapperEngine* pEngine | ||
12 | ) | ||
13 | { | ||
14 | pEngine->AddRef(); | ||
15 | |||
16 | ReleaseObject(vpEngine); | ||
17 | vpEngine = pEngine; | ||
18 | } | ||
19 | |||
20 | DAPI_(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 | |||
39 | LExit: | ||
40 | ReleaseObject(pEngine); | ||
41 | |||
42 | return hr; | ||
43 | } | ||
44 | |||
45 | |||
46 | DAPI_(void) BalUninitialize() | ||
47 | { | ||
48 | ReleaseNullObject(vpEngine); | ||
49 | } | ||
50 | |||
51 | |||
52 | DAPI_(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 | |||
66 | LExit: | ||
67 | ReleaseStr(sczPath); | ||
68 | return hr; | ||
69 | } | ||
70 | |||
71 | |||
72 | DAPI_(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 | |||
87 | LExit: | ||
88 | return hr; | ||
89 | } | ||
90 | |||
91 | |||
92 | // The contents of psczOut may be sensitive, should keep encrypted and SecureZeroFree. | ||
93 | DAPI_(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 | |||
124 | LExit: | ||
125 | return hr; | ||
126 | } | ||
127 | |||
128 | |||
129 | // The contents of pllValue may be sensitive, if variable is hidden should keep value encrypted and SecureZeroMemory. | ||
130 | DAPI_(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 | |||
145 | LExit: | ||
146 | return hr; | ||
147 | } | ||
148 | |||
149 | |||
150 | DAPI_(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 | |||
165 | LExit: | ||
166 | return hr; | ||
167 | } | ||
168 | |||
169 | |||
170 | DAPI_(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 | |||
185 | LExit: | ||
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. | ||
191 | DAPI_(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 | |||
222 | LExit: | ||
223 | return hr; | ||
224 | } | ||
225 | |||
226 | DAPI_(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 | |||
241 | LExit: | ||
242 | return hr; | ||
243 | } | ||
244 | |||
245 | |||
246 | DAPIV_(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 | |||
273 | LExit: | ||
274 | ReleaseStr(sczMessage); | ||
275 | ReleaseStr(sczFormattedAnsi); | ||
276 | return hr; | ||
277 | } | ||
278 | |||
279 | |||
280 | DAPIV_(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 | |||
307 | LExit: | ||
308 | ReleaseStr(sczMessage); | ||
309 | ReleaseStr(sczFormattedAnsi); | ||
310 | return hr; | ||
311 | } | ||
312 | |||
313 | DAPIV_(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 | |||
333 | LExit: | ||
334 | return hr; | ||
335 | } | ||
336 | |||
337 | DAPI_(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 | |||
375 | LExit: | ||
376 | if (pwz) | ||
377 | { | ||
378 | ::LocalFree(pwz); | ||
379 | } | ||
380 | |||
381 | return hr; | ||
382 | } | ||