@joebigelow / wix-1 / commits / a645cabc

Use balutil methods in Engine.cs to avoid size_t ugliness.

Sean Hall committed May 7, 2021 at 16:37 UTC a645cabc7a46adaa8f26d913bbb3cc5f9cd07820
11 files changed +466 -201
src/api/burn/WixToolset.Mba.Core/BalUtil.cs
+30 -7
@@ -7,16 +7,39 @@ namespace WixToolset.Mba.Core
7
8 internal static class BalUtil
9 {
10 - [DllImport("mbanative.dll", ExactSpelling = true, PreserveSig = false)]
11 - internal static extern IBootstrapperEngine InitializeFromCreateArgs(
12 - IntPtr pArgs,
13 - ref Command pCommand
10 + [DllImport("mbanative.dll", ExactSpelling = true)]
11 + internal static extern int BalEscapeStringFromEngine(
12 + [MarshalAs(UnmanagedType.Interface)] IBootstrapperEngine pEngine,
13 + [MarshalAs(UnmanagedType.LPWStr)] string wzIn,
14 + ref StrUtil.StrHandle psczOut
15 + );
16 +
17 + [DllImport("mbanative.dll", ExactSpelling = true)]
18 + internal static extern int BalFormatStringFromEngine(
19 + [MarshalAs(UnmanagedType.Interface)] IBootstrapperEngine pEngine,
20 + [MarshalAs(UnmanagedType.LPWStr)] string wzFormat,
21 + ref StrUtil.StrHandle psczOut
22 + );
23 +
24 + [DllImport("mbanative.dll", ExactSpelling = true)]
25 + internal static extern int BalGetStringVariableFromEngine(
26 + [MarshalAs(UnmanagedType.Interface)] IBootstrapperEngine pEngine,
27 + [MarshalAs(UnmanagedType.LPWStr)] string wzVariable,
28 + ref StrUtil.StrHandle psczOut
29 + );
30 +
31 + [DllImport("mbanative.dll", ExactSpelling = true)]
32 + internal static extern int BalGetVersionVariableFromEngine(
33 + [MarshalAs(UnmanagedType.Interface)] IBootstrapperEngine pEngine,
34 + [MarshalAs(UnmanagedType.LPWStr)] string wzVariable,
35 + ref StrUtil.StrHandle psczOut
36 );
37
38 [DllImport("mbanative.dll", ExactSpelling = true)]
17 - internal static extern void StoreBAInCreateResults(
18 - IntPtr pResults,
19 - [MarshalAs(UnmanagedType.Interface)] IBootstrapperApplication pBA
39 + [return: MarshalAs(UnmanagedType.Bool)]
40 + internal static extern bool BalVariableExistsFromEngine(
41 + [MarshalAs(UnmanagedType.Interface)] IBootstrapperEngine pEngine,
42 + [MarshalAs(UnmanagedType.LPWStr)] string wzVariable
43 );
44 }
45 }
src/api/burn/WixToolset.Mba.Core/BaseBootstrapperApplicationFactory.cs
+2 -2
@@ -44,7 +44,7 @@ namespace WixToolset.Mba.Core
44 {
45 cbSize = Marshal.SizeOf(typeof(Command))
46 };
47 - var pEngine = BalUtil.InitializeFromCreateArgs(pArgs, ref pCommand);
47 + var pEngine = MbaNative.InitializeFromCreateArgs(pArgs, ref pCommand);
48 engine = new Engine(pEngine);
49 bootstrapperCommand = pCommand.GetBootstrapperCommand();
50 }
@@ -57,7 +57,7 @@ namespace WixToolset.Mba.Core
57 /// <param name="ba">The <see cref="IBootstrapperApplication"/>.</param>
58 public static void StoreBAInCreateResults(IntPtr pResults, IBootstrapperApplication ba)
59 {
60 - BalUtil.StoreBAInCreateResults(pResults, ba);
60 + MbaNative.StoreBAInCreateResults(pResults, ba);
61 }
62 }
63 }
src/api/burn/WixToolset.Mba.Core/Engine.cs
+50 -179
@@ -13,8 +13,6 @@ namespace WixToolset.Mba.Core
13 /// </summary>
14 public sealed class Engine : IEngine
15 {
16 - // Burn errs on empty strings, so declare initial buffer size.
17 - private const int InitialBufferSize = 80;
16 private static readonly string normalizeVersionFormatString = "{0} must be less than or equal to " + UInt16.MaxValue;
17
18 private IBootstrapperEngine engine;
@@ -62,9 +60,7 @@ namespace WixToolset.Mba.Core
60 /// <inheritdoc/>
61 public bool ContainsVariable(string name)
62 {
65 - IntPtr capacity = new IntPtr(0);
66 - int ret = this.engine.GetVariableString(name, IntPtr.Zero, ref capacity);
67 - return NativeMethods.E_NOTFOUND != ret;
63 + return BalUtil.BalVariableExistsFromEngine(this.engine, name);
64 }
65
66 /// <inheritdoc/>
@@ -101,24 +97,21 @@ namespace WixToolset.Mba.Core
97 /// <inheritdoc/>
98 public string EscapeString(string input)
99 {
104 - IntPtr capacity = new IntPtr(InitialBufferSize);
105 - StringBuilder sb = new StringBuilder(capacity.ToInt32());
106 -
107 - // Get the size of the buffer.
108 - int ret = this.engine.EscapeString(input, sb, ref capacity);
109 - if (NativeMethods.E_INSUFFICIENT_BUFFER == ret || NativeMethods.E_MOREDATA == ret)
100 + StrUtil.StrHandle handle = new StrUtil.StrHandle();
101 + try
102 {
111 - capacity = new IntPtr(capacity.ToInt32() + 1); // Add one for the null terminator.
112 - sb.Capacity = capacity.ToInt32();
113 - ret = this.engine.EscapeString(input, sb, ref capacity);
114 - }
103 + int ret = BalUtil.BalEscapeStringFromEngine(this.engine, input, ref handle);
104 + if (ret != NativeMethods.S_OK)
105 + {
106 + throw new Win32Exception(ret);
107 + }
108
116 - if (NativeMethods.S_OK != ret)
109 + return handle.ToUniString();
110 + }
111 + finally
112 {
118 - throw new Win32Exception(ret);
113 + handle.Dispose();
114 }
120 -
121 - return sb.ToString();
115 }
116
117 /// <inheritdoc/>
@@ -133,24 +126,21 @@ namespace WixToolset.Mba.Core
126 /// <inheritdoc/>
127 public string FormatString(string format)
128 {
136 - IntPtr capacity = new IntPtr(InitialBufferSize);
137 - StringBuilder sb = new StringBuilder(capacity.ToInt32());
138 -
139 - // Get the size of the buffer.
140 - int ret = this.engine.FormatString(format, sb, ref capacity);
141 - if (NativeMethods.E_INSUFFICIENT_BUFFER == ret || NativeMethods.E_MOREDATA == ret)
129 + StrUtil.StrHandle handle = new StrUtil.StrHandle();
130 + try
131 {
143 - capacity = new IntPtr(capacity.ToInt32() + 1); // Add one for the null terminator.
144 - sb.Capacity = capacity.ToInt32();
145 - ret = this.engine.FormatString(format, sb, ref capacity);
146 - }
132 + int ret = BalUtil.BalFormatStringFromEngine(this.engine, format, ref handle);
133 + if (ret != NativeMethods.S_OK)
134 + {
135 + throw new Win32Exception(ret);
136 + }
137
148 - if (NativeMethods.S_OK != ret)
138 + return handle.ToUniString();
139 + }
140 + finally
141 {
150 - throw new Win32Exception(ret);
142 + handle.Dispose();
143 }
152 -
153 - return sb.ToString();
144 }
145
146 /// <inheritdoc/>
@@ -168,53 +158,60 @@ namespace WixToolset.Mba.Core
158 /// <inheritdoc/>
159 public SecureString GetVariableSecureString(string name)
160 {
171 - var pUniString = this.getStringVariable(name, out var length);
161 + StrUtil.StrHandle handle = new StrUtil.StrHandle();
162 try
163 {
174 - return this.convertToSecureString(pUniString, length);
164 + int ret = BalUtil.BalGetStringVariableFromEngine(this.engine, name, ref handle);
165 + if (ret != NativeMethods.S_OK)
166 + {
167 + throw new Win32Exception(ret);
168 + }
169 +
170 + return handle.ToSecureString();
171 }
172 finally
173 {
178 - if (IntPtr.Zero != pUniString)
179 - {
180 - Marshal.FreeCoTaskMem(pUniString);
181 - }
174 + handle.Dispose();
175 }
176 }
177
178 /// <inheritdoc/>
179 public string GetVariableString(string name)
180 {
188 - int length;
189 - IntPtr pUniString = this.getStringVariable(name, out length);
181 + StrUtil.StrHandle handle = new StrUtil.StrHandle();
182 try
183 {
192 - return Marshal.PtrToStringUni(pUniString, length);
184 + int ret = BalUtil.BalGetStringVariableFromEngine(this.engine, name, ref handle);
185 + if (ret != NativeMethods.S_OK)
186 + {
187 + throw new Win32Exception(ret);
188 + }
189 +
190 + return handle.ToUniString();
191 }
192 finally
193 {
196 - if (IntPtr.Zero != pUniString)
197 - {
198 - Marshal.FreeCoTaskMem(pUniString);
199 - }
194 + handle.Dispose();
195 }
196 }
197
198 /// <inheritdoc/>
199 public string GetVariableVersion(string name)
200 {
206 - int length;
207 - IntPtr pUniString = this.getVersionVariable(name, out length);
201 + StrUtil.StrHandle handle = new StrUtil.StrHandle();
202 try
203 {
210 - return Marshal.PtrToStringUni(pUniString, length);
204 + int ret = BalUtil.BalGetVersionVariableFromEngine(this.engine, name, ref handle);
205 + if (ret != NativeMethods.S_OK)
206 + {
207 + throw new Win32Exception(ret);
208 + }
209 +
210 + return handle.ToUniString();
211 }
212 finally
213 {
214 - if (IntPtr.Zero != pUniString)
215 - {
216 - Marshal.FreeCoTaskMem(pUniString);
217 - }
214 + handle.Dispose();
215 }
216 }
217
@@ -336,132 +333,6 @@ namespace WixToolset.Mba.Core
333 this.engine.Quit(exitCode);
334 }
335
339 - /// <summary>
340 - /// Gets the variable given by <paramref name="name"/> as a string.
341 - /// </summary>
342 - /// <param name="name">The name of the variable to get.</param>
343 - /// <param name="length">The length of the Unicode string.</param>
344 - /// <returns>The value by a pointer to a Unicode string. Must be freed by Marshal.FreeCoTaskMem.</returns>
345 - /// <exception cref="Exception">An error occurred getting the variable.</exception>
346 - internal IntPtr getStringVariable(string name, out int length)
347 - {
348 - IntPtr capacity = new IntPtr(InitialBufferSize);
349 - bool success = false;
350 - IntPtr pValue = Marshal.AllocCoTaskMem(capacity.ToInt32() * UnicodeEncoding.CharSize);
351 - try
352 - {
353 - // Get the size of the buffer.
354 - int ret = this.engine.GetVariableString(name, pValue, ref capacity);
355 - if (NativeMethods.E_INSUFFICIENT_BUFFER == ret || NativeMethods.E_MOREDATA == ret)
356 - {
357 - // Don't need to add 1 for the null terminator, the engine already includes that.
358 - pValue = Marshal.ReAllocCoTaskMem(pValue, capacity.ToInt32() * UnicodeEncoding.CharSize);
359 - ret = this.engine.GetVariableString(name, pValue, ref capacity);
360 - }
361 -
362 - if (NativeMethods.S_OK != ret)
363 - {
364 - throw Marshal.GetExceptionForHR(ret);
365 - }
366 -
367 - // The engine only returns the exact length of the string if the buffer was too small, so calculate it ourselves.
368 - int maxLength = capacity.ToInt32();
369 - for (length = 0; length < maxLength; ++length)
370 - {
371 - if (0 == Marshal.ReadInt16(pValue, length * UnicodeEncoding.CharSize))
372 - {
373 - break;
374 - }
375 - }
376 -
377 - success = true;
378 - return pValue;
379 - }
380 - finally
381 - {
382 - if (!success && IntPtr.Zero != pValue)
383 - {
384 - Marshal.FreeCoTaskMem(pValue);
385 - }
386 - }
387 - }
388 -
389 - /// <summary>
390 - /// Gets the variable given by <paramref name="name"/> as a version string.
391 - /// </summary>
392 - /// <param name="name">The name of the variable to get.</param>
393 - /// <param name="length">The length of the Unicode string.</param>
394 - /// <returns>The value by a pointer to a Unicode string. Must be freed by Marshal.FreeCoTaskMem.</returns>
395 - /// <exception cref="Exception">An error occurred getting the variable.</exception>
396 - internal IntPtr getVersionVariable(string name, out int length)
397 - {
398 - IntPtr capacity = new IntPtr(InitialBufferSize);
399 - bool success = false;
400 - IntPtr pValue = Marshal.AllocCoTaskMem(capacity.ToInt32() * UnicodeEncoding.CharSize);
401 - try
402 - {
403 - // Get the size of the buffer.
404 - int ret = this.engine.GetVariableVersion(name, pValue, ref capacity);
405 - if (NativeMethods.E_INSUFFICIENT_BUFFER == ret || NativeMethods.E_MOREDATA == ret)
406 - {
407 - // Don't need to add 1 for the null terminator, the engine already includes that.
408 - pValue = Marshal.ReAllocCoTaskMem(pValue, capacity.ToInt32() * UnicodeEncoding.CharSize);
409 - ret = this.engine.GetVariableVersion(name, pValue, ref capacity);
410 - }
411 -
412 - if (NativeMethods.S_OK != ret)
413 - {
414 - throw Marshal.GetExceptionForHR(ret);
415 - }
416 -
417 - // The engine only returns the exact length of the string if the buffer was too small, so calculate it ourselves.
418 - int maxLength = capacity.ToInt32();
419 - for (length = 0; length < maxLength; ++length)
420 - {
421 - if (0 == Marshal.ReadInt16(pValue, length * UnicodeEncoding.CharSize))
422 - {
423 - break;
424 - }
425 - }
426 -
427 - success = true;
428 - return pValue;
429 - }
430 - finally
431 - {
432 - if (!success && IntPtr.Zero != pValue)
433 - {
434 - Marshal.FreeCoTaskMem(pValue);
435 - }
436 - }
437 - }
438 -
439 - /// <summary>
440 - /// Initialize a SecureString with the given Unicode string.
441 - /// </summary>
442 - /// <param name="pUniString">Pointer to Unicode string.</param>
443 - /// <param name="length">The string's length.</param>
444 - internal SecureString convertToSecureString(IntPtr pUniString, int length)
445 - {
446 - if (IntPtr.Zero == pUniString)
447 - {
448 - return null;
449 - }
450 -
451 - SecureString value = new SecureString();
452 - short s;
453 - char c;
454 - for (int charIndex = 0; charIndex < length; charIndex++)
455 - {
456 - s = Marshal.ReadInt16(pUniString, charIndex * UnicodeEncoding.CharSize);
457 - c = (char)s;
458 - value.AppendChar(c);
459 - s = 0;
460 - c = (char)0;
461 - }
462 - return value;
463 - }
464 -
336 /// <summary>
337 /// Utility method for converting a <see cref="Version"/> into a <see cref="long"/>.
338 /// </summary>
src/api/burn/WixToolset.Mba.Core/MbaNative.cs new
+22
@@ -0,0 +1,22 @@
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 +namespace WixToolset.Mba.Core
4 +{
5 + using System;
6 + using System.Runtime.InteropServices;
7 +
8 + internal static class MbaNative
9 + {
10 + [DllImport("mbanative.dll", ExactSpelling = true, PreserveSig = false)]
11 + internal static extern IBootstrapperEngine InitializeFromCreateArgs(
12 + IntPtr pArgs,
13 + ref Command pCommand
14 + );
15 +
16 + [DllImport("mbanative.dll", ExactSpelling = true)]
17 + internal static extern void StoreBAInCreateResults(
18 + IntPtr pResults,
19 + [MarshalAs(UnmanagedType.Interface)] IBootstrapperApplication pBA
20 + );
21 + }
22 +}
src/api/burn/WixToolset.Mba.Core/NativeMethods.cs
+12
@@ -34,4 +34,16 @@ namespace WixToolset.Mba.Core
34 );
35 #endregion
36 }
37 +
38 + #region SafeHandles
39 + internal abstract class SafeHandleZeroIsDefaultAndInvalid : SafeHandle
40 + {
41 + public SafeHandleZeroIsDefaultAndInvalid() : base(IntPtr.Zero, true) { }
42 +
43 + public override bool IsInvalid
44 + {
45 + get { return this.handle == IntPtr.Zero; }
46 + }
47 + }
48 + #endregion
49 }
src/api/burn/WixToolset.Mba.Core/StrUtil.cs new
+54
@@ -0,0 +1,54 @@
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 +namespace WixToolset.Mba.Core
4 +{
5 + using System;
6 + using System.Runtime.InteropServices;
7 + using System.Security;
8 + using System.Text;
9 +
10 + internal static class StrUtil
11 + {
12 + [DllImport("mbanative.dll", ExactSpelling = true)]
13 + internal static extern void StrFree(
14 + IntPtr scz
15 + );
16 +
17 + internal sealed class StrHandle : SafeHandleZeroIsDefaultAndInvalid
18 + {
19 + protected override bool ReleaseHandle()
20 + {
21 + StrFree(this.handle);
22 + return true;
23 + }
24 +
25 + public string ToUniString()
26 + {
27 + return Marshal.PtrToStringUni(this.handle);
28 + }
29 +
30 + public SecureString ToSecureString()
31 + {
32 + if (this.handle == IntPtr.Zero)
33 + {
34 + return null;
35 + }
36 +
37 + SecureString value = new SecureString();
38 + char c;
39 + for (int charIndex = 0; ; charIndex++)
40 + {
41 + c = (char)Marshal.ReadInt16(this.handle, charIndex * UnicodeEncoding.CharSize);
42 + if (c == '\0')
43 + {
44 + break;
45 + }
46 +
47 + value.AppendChar(c);
48 + }
49 +
50 + return value;
51 + }
52 + }
53 + }
54 +}
src/api/burn/WixToolset.Mba.Core/VerUtil.cs
+1 -5
@@ -83,12 +83,8 @@ namespace WixToolset.Mba.Core
83 }
84 }
85
86 - internal sealed class VersionHandle : SafeHandle
86 + internal sealed class VersionHandle : SafeHandleZeroIsDefaultAndInvalid
87 {
88 - public VersionHandle() : base(IntPtr.Zero, true) { }
89 -
90 - public override bool IsInvalid => false;
91 -
88 protected override bool ReleaseHandle()
89 {
90 VerFreeVersion(this.handle);
src/api/burn/balutil/balutil.cpp
+205 -8
@@ -89,6 +89,66 @@ LExit:
89 }
90
91
92 +DAPI_(HRESULT) BalEscapeString(
93 + __in_z LPCWSTR wzIn,
94 + __inout LPWSTR* psczOut
95 + )
96 +{
97 + HRESULT hr = S_OK;
98 +
99 + if (!vpEngine)
100 + {
101 + hr = E_POINTER;
102 + ExitOnRootFailure(hr, "BalInitialize() must be called first.");
103 + }
104 +
105 + hr = BalEscapeStringFromEngine(vpEngine, wzIn, psczOut);
106 +
107 +LExit:
108 + return hr;
109 +}
110 +
111 +
112 +DAPI_(HRESULT) BalEscapeStringFromEngine(
113 + __in IBootstrapperEngine* pEngine,
114 + __in_z LPCWSTR wzIn,
115 + __inout LPWSTR* psczOut
116 + )
117 +{
118 + HRESULT hr = S_OK;
119 + SIZE_T cch = 0;
120 +
121 + if (*psczOut)
122 + {
123 + hr = StrMaxLength(*psczOut, &cch);
124 + ExitOnFailure(hr, "Failed to determine length of value.");
125 + }
126 + else
127 + {
128 + hr = ::StringCchLengthW(wzIn, STRSAFE_MAX_LENGTH, reinterpret_cast<size_t*>(&cch));
129 + ExitOnFailure(hr, "Failed to determine length of source.");
130 +
131 + cch = min(STRSAFE_MAX_LENGTH, cch + VARIABLE_GROW_FACTOR);
132 + hr = StrAlloc(psczOut, cch);
133 + ExitOnFailure(hr, "Failed to pre-allocate value.");
134 + }
135 +
136 + hr = pEngine->EscapeString(wzIn, *psczOut, &cch);
137 + if (E_MOREDATA == hr)
138 + {
139 + ++cch;
140 +
141 + hr = StrAllocSecure(psczOut, cch);
142 + ExitOnFailure(hr, "Failed to allocate value.");
143 +
144 + hr = pEngine->EscapeString(wzIn, *psczOut, &cch);
145 + }
146 +
147 +LExit:
148 + return hr;
149 +}
150 +
151 +
152 // The contents of psczOut may be sensitive, should keep encrypted and SecureZeroFree.
153 DAPI_(HRESULT) BalFormatString(
154 __in_z LPCWSTR wzFormat,
@@ -96,7 +156,6 @@ DAPI_(HRESULT) BalFormatString(
156 )
157 {
158 HRESULT hr = S_OK;
99 - SIZE_T cch = 0;
159
160 if (!vpEngine)
161 {
@@ -104,13 +163,39 @@ DAPI_(HRESULT) BalFormatString(
163 ExitOnRootFailure(hr, "BalInitialize() must be called first.");
164 }
165
166 + hr = BalFormatStringFromEngine(vpEngine, wzFormat, psczOut);
167 +
168 +LExit:
169 + return hr;
170 +}
171 +
172 +
173 +// The contents of psczOut may be sensitive, should keep encrypted and SecureZeroFree.
174 +DAPI_(HRESULT) BalFormatStringFromEngine(
175 + __in IBootstrapperEngine* pEngine,
176 + __in_z LPCWSTR wzFormat,
177 + __inout LPWSTR* psczOut
178 + )
179 +{
180 + HRESULT hr = S_OK;
181 + SIZE_T cch = 0;
182 +
183 if (*psczOut)
184 {
185 hr = StrMaxLength(*psczOut, &cch);
186 ExitOnFailure(hr, "Failed to determine length of value.");
187 }
188 + else
189 + {
190 + hr = ::StringCchLengthW(wzFormat, STRSAFE_MAX_LENGTH, reinterpret_cast<size_t*>(&cch));
191 + ExitOnFailure(hr, "Failed to determine length of source.");
192 +
193 + cch = min(STRSAFE_MAX_LENGTH, cch + VARIABLE_GROW_FACTOR);
194 + hr = StrAlloc(psczOut, cch);
195 + ExitOnFailure(hr, "Failed to pre-allocate value.");
196 + }
197
113 - hr = vpEngine->FormatString(wzFormat, *psczOut, &cch);
198 + hr = pEngine->FormatString(wzFormat, *psczOut, &cch);
199 if (E_MOREDATA == hr)
200 {
201 ++cch;
@@ -118,7 +203,7 @@ DAPI_(HRESULT) BalFormatString(
203 hr = StrAllocSecure(psczOut, cch);
204 ExitOnFailure(hr, "Failed to allocate value.");
205
121 - hr = vpEngine->FormatString(wzFormat, *psczOut, &cch);
206 + hr = pEngine->FormatString(wzFormat, *psczOut, &cch);
207 }
208
209 LExit:
@@ -172,7 +257,7 @@ DAPI_(BOOL) BalVariableExists(
257 )
258 {
259 HRESULT hr = S_OK;
175 - SIZE_T cch = 0;
260 + BOOL fExists = FALSE;
261
262 if (!vpEngine)
263 {
@@ -180,9 +265,23 @@ DAPI_(BOOL) BalVariableExists(
265 ExitOnRootFailure(hr, "BalInitialize() must be called first.");
266 }
267
183 - hr = vpEngine->GetVariableString(wzVariable, NULL, &cch);
268 + fExists = BalVariableExistsFromEngine(vpEngine, wzVariable);
269
270 LExit:
271 + return fExists;
272 +}
273 +
274 +
275 +DAPI_(BOOL) BalVariableExistsFromEngine(
276 + __in IBootstrapperEngine* pEngine,
277 + __in_z LPCWSTR wzVariable
278 + )
279 +{
280 + HRESULT hr = S_OK;
281 + SIZE_T cch = 0;
282 +
283 + hr = pEngine->GetVariableString(wzVariable, NULL, &cch);
284 +
285 return E_NOTFOUND != hr;
286 }
287
@@ -194,7 +293,6 @@ DAPI_(HRESULT) BalGetStringVariable(
293 )
294 {
295 HRESULT hr = S_OK;
197 - SIZE_T cch = 0;
296
297 if (!vpEngine)
298 {
@@ -202,13 +300,36 @@ DAPI_(HRESULT) BalGetStringVariable(
300 ExitOnRootFailure(hr, "BalInitialize() must be called first.");
301 }
302
303 + hr = BalGetStringVariableFromEngine(vpEngine, wzVariable, psczValue);
304 +
305 +LExit:
306 + return hr;
307 +}
308 +
309 +
310 +// The contents of psczValue may be sensitive, if variable is hidden should keep value encrypted and SecureZeroFree.
311 +DAPI_(HRESULT) BalGetStringVariableFromEngine(
312 + __in IBootstrapperEngine* pEngine,
313 + __in_z LPCWSTR wzVariable,
314 + __inout LPWSTR* psczValue
315 + )
316 +{
317 + HRESULT hr = S_OK;
318 + SIZE_T cch = 0;
319 +
320 if (*psczValue)
321 {
322 hr = StrMaxLength(*psczValue, &cch);
323 ExitOnFailure(hr, "Failed to determine length of value.");
324 }
325 + else
326 + {
327 + cch = VARIABLE_GROW_FACTOR;
328 + hr = StrAlloc(psczValue, cch);
329 + ExitOnFailure(hr, "Failed to pre-allocate value.");
330 + }
331
211 - hr = vpEngine->GetVariableString(wzVariable, *psczValue, &cch);
332 + hr = pEngine->GetVariableString(wzVariable, *psczValue, &cch);
333 if (E_MOREDATA == hr)
334 {
335 ++cch;
@@ -216,7 +337,7 @@ DAPI_(HRESULT) BalGetStringVariable(
337 hr = StrAllocSecure(psczValue, cch);
338 ExitOnFailure(hr, "Failed to allocate value.");
339
219 - hr = vpEngine->GetVariableString(wzVariable, *psczValue, &cch);
340 + hr = pEngine->GetVariableString(wzVariable, *psczValue, &cch);
341 }
342
343 LExit:
@@ -244,6 +365,82 @@ LExit:
365 }
366
367
368 +DAPI_(HRESULT) BalGetVersionVariable(
369 + __in_z LPCWSTR wzVariable,
370 + __inout LPWSTR* psczValue
371 + )
372 +{
373 + HRESULT hr = S_OK;
374 +
375 + if (!vpEngine)
376 + {
377 + hr = E_POINTER;
378 + ExitOnRootFailure(hr, "BalInitialize() must be called first.");
379 + }
380 +
381 + hr = BalGetVersionVariableFromEngine(vpEngine, wzVariable, psczValue);
382 +
383 +LExit:
384 + return hr;
385 +}
386 +
387 +
388 +DAPI_(HRESULT) BalGetVersionVariableFromEngine(
389 + __in IBootstrapperEngine* pEngine,
390 + __in_z LPCWSTR wzVariable,
391 + __inout LPWSTR* psczValue
392 + )
393 +{
394 + HRESULT hr = S_OK;
395 + SIZE_T cch = 0;
396 +
397 + if (*psczValue)
398 + {
399 + hr = StrMaxLength(*psczValue, &cch);
400 + ExitOnFailure(hr, "Failed to determine length of value.");
401 + }
402 + else
403 + {
404 + cch = VARIABLE_GROW_FACTOR;
405 + hr = StrAlloc(psczValue, cch);
406 + ExitOnFailure(hr, "Failed to pre-allocate value.");
407 + }
408 +
409 + hr = pEngine->GetVariableVersion(wzVariable, *psczValue, &cch);
410 + if (E_MOREDATA == hr)
411 + {
412 + ++cch;
413 +
414 + hr = StrAllocSecure(psczValue, cch);
415 + ExitOnFailure(hr, "Failed to allocate value.");
416 +
417 + hr = pEngine->GetVariableVersion(wzVariable, *psczValue, &cch);
418 + }
419 +
420 +LExit:
421 + return hr;
422 +}
423 +
424 +DAPI_(HRESULT) BalSetVersionVariable(
425 + __in_z LPCWSTR wzVariable,
426 + __in_z_opt LPCWSTR wzValue
427 + )
428 +{
429 + HRESULT hr = S_OK;
430 +
431 + if (!vpEngine)
432 + {
433 + hr = E_POINTER;
434 + ExitOnRootFailure(hr, "BalInitialize() must be called first.");
435 + }
436 +
437 + hr = vpEngine->SetVariableVersion(wzVariable, wzValue);
438 +
439 +LExit:
440 + return hr;
441 +}
442 +
443 +
444 DAPIV_(HRESULT) BalLog(
445 __in BOOTSTRAPPER_LOG_LEVEL level,
446 __in_z __format_string LPCSTR szFormat,
src/api/burn/balutil/inc/balutil.h
+83
@@ -78,6 +78,27 @@ DAPI_(HRESULT) BalEvaluateCondition(
78 __out BOOL* pf
79 );
80
81 +/*******************************************************************
82 +BalEscapeString - escapes a string to use as part of a formatted string variable.
83 +
84 + Note: Use StrFree() to release psczOut.
85 +********************************************************************/
86 +DAPI_(HRESULT) BalEscapeString(
87 + __in_z LPCWSTR wzIn,
88 + __inout LPWSTR* psczOut
89 + );
90 +
91 +/*******************************************************************
92 +BalEscapeStringFromEngine - escapes a string to use as part of a formatted string variable.
93 +
94 + Note: Use StrFree() to release psczOut.
95 +********************************************************************/
96 +DAPI_(HRESULT) BalEscapeStringFromEngine(
97 + __in IBootstrapperEngine* pEngine,
98 + __in_z LPCWSTR wzIn,
99 + __inout LPWSTR* psczOut
100 + );
101 +
102 /*******************************************************************
103 BalFormatString - formats a string using variables in the engine.
104
@@ -88,6 +109,17 @@ DAPI_(HRESULT) BalFormatString(
109 __inout LPWSTR* psczOut
110 );
111
112 +/*******************************************************************
113 +BalFormatStringFromEngine - formats a string using variables in the engine.
114 +
115 + Note: Use StrFree() to release psczOut.
116 +********************************************************************/
117 +DAPI_(HRESULT) BalFormatStringFromEngine(
118 + __in IBootstrapperEngine* pEngine,
119 + __in_z LPCWSTR wzFormat,
120 + __inout LPWSTR* psczOut
121 + );
122 +
123 /*******************************************************************
124 BalGetNumericVariable - gets a number from a variable in the engine.
125
@@ -115,6 +147,15 @@ DAPI_(BOOL) BalVariableExists(
147 __in_z LPCWSTR wzVariable
148 );
149
150 +/*******************************************************************
151 +BalVariableExistsFromEngine - checks if a variable exists in the engine.
152 +
153 +********************************************************************/
154 +DAPI_(BOOL) BalVariableExistsFromEngine(
155 + __in IBootstrapperEngine* pEngine,
156 + __in_z LPCWSTR wzVariable
157 + );
158 +
159 /*******************************************************************
160 BalGetStringVariable - gets a string from a variable in the engine.
161
@@ -125,8 +166,20 @@ DAPI_(HRESULT) BalGetStringVariable(
166 __inout LPWSTR* psczValue
167 );
168
169 +/*******************************************************************
170 +BalGetStringVariableFromEngine - gets a string from a variable in the engine.
171 +
172 + Note: Use StrFree() to release psczValue.
173 +********************************************************************/
174 +DAPI_(HRESULT) BalGetStringVariableFromEngine(
175 + __in IBootstrapperEngine* pEngine,
176 + __in_z LPCWSTR wzVariable,
177 + __inout LPWSTR* psczValue
178 + );
179 +
180 /*******************************************************************
181 BalSetStringVariable - sets a string variable in the engine.
182 + If the value contains unexpanded variables, set fFormatted to true.
183
184 ********************************************************************/
185 DAPI_(HRESULT) BalSetStringVariable(
@@ -135,6 +188,36 @@ DAPI_(HRESULT) BalSetStringVariable(
188 __in BOOL fFormatted
189 );
190
191 +/*******************************************************************
192 +BalGetVersionVariable - gets a version from a variable in the engine.
193 +
194 + Note: Use StrFree() to release psczValue.
195 +********************************************************************/
196 +DAPI_(HRESULT) BalGetVersionVariable(
197 + __in_z LPCWSTR wzVariable,
198 + __inout LPWSTR* psczValue
199 + );
200 +
201 +/*******************************************************************
202 +BalGetVersionVariableFromEngine - gets a version from a variable in the engine.
203 +
204 + Note: Use StrFree() to release psczValue.
205 +********************************************************************/
206 +DAPI_(HRESULT) BalGetVersionVariableFromEngine(
207 + __in IBootstrapperEngine* pEngine,
208 + __in_z LPCWSTR wzVariable,
209 + __inout LPWSTR* psczValue
210 + );
211 +
212 +/*******************************************************************
213 +BalSetVersionVariable - sets a version variable in the engine.
214 +
215 +********************************************************************/
216 +DAPI_(HRESULT) BalSetVersionVariable(
217 + __in_z LPCWSTR wzVariable,
218 + __in_z_opt LPCWSTR wzValue
219 + );
220 +
221 /*******************************************************************
222 BalLog - logs a message with the engine.
223
src/api/burn/balutil/precomp.h
+1
@@ -7,6 +7,7 @@
7 #include <msi.h>
8 #include <wininet.h>
9 #include <CommCtrl.h>
10 +#include <strsafe.h>
11
12 #include <dutil.h>
13 #include <pathutil.h>
src/api/burn/mbanative/mbanative.def
+6
@@ -2,8 +2,14 @@
2
3
4 EXPORTS
5 + BalEscapeStringFromEngine
6 + BalFormatStringFromEngine
7 + BalGetStringVariableFromEngine
8 + BalGetVersionVariableFromEngine
9 + BalVariableExistsFromEngine
10 InitializeFromCreateArgs
11 StoreBAInCreateResults
12 + StrFree
13 VerCompareParsedVersions
14 VerCompareStringVersions
15 VerCopyVersion