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