aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSean Hall <r.sean.hall@gmail.com>2021-05-07 16:37:19 -0500
committerSean Hall <r.sean.hall@gmail.com>2021-05-11 19:11:19 -0500
commita645cabc7a46adaa8f26d913bbb3cc5f9cd07820 (patch)
treefdfbc63bb4a24bf17d123c5e3ffe8b509d2d5176
parent27c6decae94536cae338731b6cb765aa92776486 (diff)
downloadwix-a645cabc7a46adaa8f26d913bbb3cc5f9cd07820.tar.gz
wix-a645cabc7a46adaa8f26d913bbb3cc5f9cd07820.tar.bz2
wix-a645cabc7a46adaa8f26d913bbb3cc5f9cd07820.zip
Use balutil methods in Engine.cs to avoid size_t ugliness.
-rw-r--r--src/api/burn/WixToolset.Mba.Core/BalUtil.cs37
-rw-r--r--src/api/burn/WixToolset.Mba.Core/BaseBootstrapperApplicationFactory.cs4
-rw-r--r--src/api/burn/WixToolset.Mba.Core/Engine.cs229
-rw-r--r--src/api/burn/WixToolset.Mba.Core/MbaNative.cs22
-rw-r--r--src/api/burn/WixToolset.Mba.Core/NativeMethods.cs12
-rw-r--r--src/api/burn/WixToolset.Mba.Core/StrUtil.cs54
-rw-r--r--src/api/burn/WixToolset.Mba.Core/VerUtil.cs6
-rw-r--r--src/api/burn/balutil/balutil.cpp213
-rw-r--r--src/api/burn/balutil/inc/balutil.h83
-rw-r--r--src/api/burn/balutil/precomp.h1
-rw-r--r--src/api/burn/mbanative/mbanative.def6
11 files changed, 466 insertions, 201 deletions
diff --git a/src/api/burn/WixToolset.Mba.Core/BalUtil.cs b/src/api/burn/WixToolset.Mba.Core/BalUtil.cs
index f478eca4..4c949a5a 100644
--- a/src/api/burn/WixToolset.Mba.Core/BalUtil.cs
+++ b/src/api/burn/WixToolset.Mba.Core/BalUtil.cs
@@ -7,16 +7,39 @@ namespace WixToolset.Mba.Core
7 7
8 internal static class BalUtil 8 internal static class BalUtil
9 { 9 {
10 [DllImport("mbanative.dll", ExactSpelling = true, PreserveSig = false)] 10 [DllImport("mbanative.dll", ExactSpelling = true)]
11 internal static extern IBootstrapperEngine InitializeFromCreateArgs( 11 internal static extern int BalEscapeStringFromEngine(
12 IntPtr pArgs, 12 [MarshalAs(UnmanagedType.Interface)] IBootstrapperEngine pEngine,
13 ref Command pCommand 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
14 ); 36 );
15 37
16 [DllImport("mbanative.dll", ExactSpelling = true)] 38 [DllImport("mbanative.dll", ExactSpelling = true)]
17 internal static extern void StoreBAInCreateResults( 39 [return: MarshalAs(UnmanagedType.Bool)]
18 IntPtr pResults, 40 internal static extern bool BalVariableExistsFromEngine(
19 [MarshalAs(UnmanagedType.Interface)] IBootstrapperApplication pBA 41 [MarshalAs(UnmanagedType.Interface)] IBootstrapperEngine pEngine,
42 [MarshalAs(UnmanagedType.LPWStr)] string wzVariable
20 ); 43 );
21 } 44 }
22} 45}
diff --git a/src/api/burn/WixToolset.Mba.Core/BaseBootstrapperApplicationFactory.cs b/src/api/burn/WixToolset.Mba.Core/BaseBootstrapperApplicationFactory.cs
index ad8a5dc0..b215681e 100644
--- a/src/api/burn/WixToolset.Mba.Core/BaseBootstrapperApplicationFactory.cs
+++ b/src/api/burn/WixToolset.Mba.Core/BaseBootstrapperApplicationFactory.cs
@@ -44,7 +44,7 @@ namespace WixToolset.Mba.Core
44 { 44 {
45 cbSize = Marshal.SizeOf(typeof(Command)) 45 cbSize = Marshal.SizeOf(typeof(Command))
46 }; 46 };
47 var pEngine = BalUtil.InitializeFromCreateArgs(pArgs, ref pCommand); 47 var pEngine = MbaNative.InitializeFromCreateArgs(pArgs, ref pCommand);
48 engine = new Engine(pEngine); 48 engine = new Engine(pEngine);
49 bootstrapperCommand = pCommand.GetBootstrapperCommand(); 49 bootstrapperCommand = pCommand.GetBootstrapperCommand();
50 } 50 }
@@ -57,7 +57,7 @@ namespace WixToolset.Mba.Core
57 /// <param name="ba">The <see cref="IBootstrapperApplication"/>.</param> 57 /// <param name="ba">The <see cref="IBootstrapperApplication"/>.</param>
58 public static void StoreBAInCreateResults(IntPtr pResults, IBootstrapperApplication ba) 58 public static void StoreBAInCreateResults(IntPtr pResults, IBootstrapperApplication ba)
59 { 59 {
60 BalUtil.StoreBAInCreateResults(pResults, ba); 60 MbaNative.StoreBAInCreateResults(pResults, ba);
61 } 61 }
62 } 62 }
63} 63}
diff --git a/src/api/burn/WixToolset.Mba.Core/Engine.cs b/src/api/burn/WixToolset.Mba.Core/Engine.cs
index aed420d5..5ebada36 100644
--- a/src/api/burn/WixToolset.Mba.Core/Engine.cs
+++ b/src/api/burn/WixToolset.Mba.Core/Engine.cs
@@ -13,8 +13,6 @@ namespace WixToolset.Mba.Core
13 /// </summary> 13 /// </summary>
14 public sealed class Engine : IEngine 14 public sealed class Engine : IEngine
15 { 15 {
16 // Burn errs on empty strings, so declare initial buffer size.
17 private const int InitialBufferSize = 80;
18 private static readonly string normalizeVersionFormatString = "{0} must be less than or equal to " + UInt16.MaxValue; 16 private static readonly string normalizeVersionFormatString = "{0} must be less than or equal to " + UInt16.MaxValue;
19 17
20 private IBootstrapperEngine engine; 18 private IBootstrapperEngine engine;
@@ -62,9 +60,7 @@ namespace WixToolset.Mba.Core
62 /// <inheritdoc/> 60 /// <inheritdoc/>
63 public bool ContainsVariable(string name) 61 public bool ContainsVariable(string name)
64 { 62 {
65 IntPtr capacity = new IntPtr(0); 63 return BalUtil.BalVariableExistsFromEngine(this.engine, name);
66 int ret = this.engine.GetVariableString(name, IntPtr.Zero, ref capacity);
67 return NativeMethods.E_NOTFOUND != ret;
68 } 64 }
69 65
70 /// <inheritdoc/> 66 /// <inheritdoc/>
@@ -101,24 +97,21 @@ namespace WixToolset.Mba.Core
101 /// <inheritdoc/> 97 /// <inheritdoc/>
102 public string EscapeString(string input) 98 public string EscapeString(string input)
103 { 99 {
104 IntPtr capacity = new IntPtr(InitialBufferSize); 100 StrUtil.StrHandle handle = new StrUtil.StrHandle();
105 StringBuilder sb = new StringBuilder(capacity.ToInt32()); 101 try
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)
110 { 102 {
111 capacity = new IntPtr(capacity.ToInt32() + 1); // Add one for the null terminator. 103 int ret = BalUtil.BalEscapeStringFromEngine(this.engine, input, ref handle);
112 sb.Capacity = capacity.ToInt32(); 104 if (ret != NativeMethods.S_OK)
113 ret = this.engine.EscapeString(input, sb, ref capacity); 105 {
114 } 106 throw new Win32Exception(ret);
107 }
115 108
116 if (NativeMethods.S_OK != ret) 109 return handle.ToUniString();
110 }
111 finally
117 { 112 {
118 throw new Win32Exception(ret); 113 handle.Dispose();
119 } 114 }
120
121 return sb.ToString();
122 } 115 }
123 116
124 /// <inheritdoc/> 117 /// <inheritdoc/>
@@ -133,24 +126,21 @@ namespace WixToolset.Mba.Core
133 /// <inheritdoc/> 126 /// <inheritdoc/>
134 public string FormatString(string format) 127 public string FormatString(string format)
135 { 128 {
136 IntPtr capacity = new IntPtr(InitialBufferSize); 129 StrUtil.StrHandle handle = new StrUtil.StrHandle();
137 StringBuilder sb = new StringBuilder(capacity.ToInt32()); 130 try
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)
142 { 131 {
143 capacity = new IntPtr(capacity.ToInt32() + 1); // Add one for the null terminator. 132 int ret = BalUtil.BalFormatStringFromEngine(this.engine, format, ref handle);
144 sb.Capacity = capacity.ToInt32(); 133 if (ret != NativeMethods.S_OK)
145 ret = this.engine.FormatString(format, sb, ref capacity); 134 {
146 } 135 throw new Win32Exception(ret);
136 }
147 137
148 if (NativeMethods.S_OK != ret) 138 return handle.ToUniString();
139 }
140 finally
149 { 141 {
150 throw new Win32Exception(ret); 142 handle.Dispose();
151 } 143 }
152
153 return sb.ToString();
154 } 144 }
155 145
156 /// <inheritdoc/> 146 /// <inheritdoc/>
@@ -168,53 +158,60 @@ namespace WixToolset.Mba.Core
168 /// <inheritdoc/> 158 /// <inheritdoc/>
169 public SecureString GetVariableSecureString(string name) 159 public SecureString GetVariableSecureString(string name)
170 { 160 {
171 var pUniString = this.getStringVariable(name, out var length); 161 StrUtil.StrHandle handle = new StrUtil.StrHandle();
172 try 162 try
173 { 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();
175 } 171 }
176 finally 172 finally
177 { 173 {
178 if (IntPtr.Zero != pUniString) 174 handle.Dispose();
179 {
180 Marshal.FreeCoTaskMem(pUniString);
181 }
182 } 175 }
183 } 176 }
184 177
185 /// <inheritdoc/> 178 /// <inheritdoc/>
186 public string GetVariableString(string name) 179 public string GetVariableString(string name)
187 { 180 {
188 int length; 181 StrUtil.StrHandle handle = new StrUtil.StrHandle();
189 IntPtr pUniString = this.getStringVariable(name, out length);
190 try 182 try
191 { 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();
193 } 191 }
194 finally 192 finally
195 { 193 {
196 if (IntPtr.Zero != pUniString) 194 handle.Dispose();
197 {
198 Marshal.FreeCoTaskMem(pUniString);
199 }
200 } 195 }
201 } 196 }
202 197
203 /// <inheritdoc/> 198 /// <inheritdoc/>
204 public string GetVariableVersion(string name) 199 public string GetVariableVersion(string name)
205 { 200 {
206 int length; 201 StrUtil.StrHandle handle = new StrUtil.StrHandle();
207 IntPtr pUniString = this.getVersionVariable(name, out length);
208 try 202 try
209 { 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 } 211 }
212 finally 212 finally
213 { 213 {
214 if (IntPtr.Zero != pUniString) 214 handle.Dispose();
215 {
216 Marshal.FreeCoTaskMem(pUniString);
217 }
218 } 215 }
219 } 216 }
220 217
@@ -337,132 +334,6 @@ namespace WixToolset.Mba.Core
337 } 334 }
338 335
339 /// <summary> 336 /// <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
465 /// <summary>
466 /// Utility method for converting a <see cref="Version"/> into a <see cref="long"/>. 337 /// Utility method for converting a <see cref="Version"/> into a <see cref="long"/>.
467 /// </summary> 338 /// </summary>
468 /// <param name="version"></param> 339 /// <param name="version"></param>
diff --git a/src/api/burn/WixToolset.Mba.Core/MbaNative.cs b/src/api/burn/WixToolset.Mba.Core/MbaNative.cs
new file mode 100644
index 00000000..a68a3907
--- /dev/null
+++ b/src/api/burn/WixToolset.Mba.Core/MbaNative.cs
@@ -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
3namespace 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}
diff --git a/src/api/burn/WixToolset.Mba.Core/NativeMethods.cs b/src/api/burn/WixToolset.Mba.Core/NativeMethods.cs
index adb2256e..45a0bc4d 100644
--- a/src/api/burn/WixToolset.Mba.Core/NativeMethods.cs
+++ b/src/api/burn/WixToolset.Mba.Core/NativeMethods.cs
@@ -34,4 +34,16 @@ namespace WixToolset.Mba.Core
34 ); 34 );
35 #endregion 35 #endregion
36 } 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
37} 49}
diff --git a/src/api/burn/WixToolset.Mba.Core/StrUtil.cs b/src/api/burn/WixToolset.Mba.Core/StrUtil.cs
new file mode 100644
index 00000000..5daef8e3
--- /dev/null
+++ b/src/api/burn/WixToolset.Mba.Core/StrUtil.cs
@@ -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
3namespace 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}
diff --git a/src/api/burn/WixToolset.Mba.Core/VerUtil.cs b/src/api/burn/WixToolset.Mba.Core/VerUtil.cs
index 81c5b716..a342f85c 100644
--- a/src/api/burn/WixToolset.Mba.Core/VerUtil.cs
+++ b/src/api/burn/WixToolset.Mba.Core/VerUtil.cs
@@ -83,12 +83,8 @@ namespace WixToolset.Mba.Core
83 } 83 }
84 } 84 }
85 85
86 internal sealed class VersionHandle : SafeHandle 86 internal sealed class VersionHandle : SafeHandleZeroIsDefaultAndInvalid
87 { 87 {
88 public VersionHandle() : base(IntPtr.Zero, true) { }
89
90 public override bool IsInvalid => false;
91
92 protected override bool ReleaseHandle() 88 protected override bool ReleaseHandle()
93 { 89 {
94 VerFreeVersion(this.handle); 90 VerFreeVersion(this.handle);
diff --git a/src/api/burn/balutil/balutil.cpp b/src/api/burn/balutil/balutil.cpp
index 7a638219..5671da4e 100644
--- a/src/api/burn/balutil/balutil.cpp
+++ b/src/api/burn/balutil/balutil.cpp
@@ -89,6 +89,66 @@ LExit:
89} 89}
90 90
91 91
92DAPI_(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
107LExit:
108 return hr;
109}
110
111
112DAPI_(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
147LExit:
148 return hr;
149}
150
151
92// The contents of psczOut may be sensitive, should keep encrypted and SecureZeroFree. 152// The contents of psczOut may be sensitive, should keep encrypted and SecureZeroFree.
93DAPI_(HRESULT) BalFormatString( 153DAPI_(HRESULT) BalFormatString(
94 __in_z LPCWSTR wzFormat, 154 __in_z LPCWSTR wzFormat,
@@ -96,7 +156,6 @@ DAPI_(HRESULT) BalFormatString(
96 ) 156 )
97{ 157{
98 HRESULT hr = S_OK; 158 HRESULT hr = S_OK;
99 SIZE_T cch = 0;
100 159
101 if (!vpEngine) 160 if (!vpEngine)
102 { 161 {
@@ -104,13 +163,39 @@ DAPI_(HRESULT) BalFormatString(
104 ExitOnRootFailure(hr, "BalInitialize() must be called first."); 163 ExitOnRootFailure(hr, "BalInitialize() must be called first.");
105 } 164 }
106 165
166 hr = BalFormatStringFromEngine(vpEngine, wzFormat, psczOut);
167
168LExit:
169 return hr;
170}
171
172
173// The contents of psczOut may be sensitive, should keep encrypted and SecureZeroFree.
174DAPI_(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
107 if (*psczOut) 183 if (*psczOut)
108 { 184 {
109 hr = StrMaxLength(*psczOut, &cch); 185 hr = StrMaxLength(*psczOut, &cch);
110 ExitOnFailure(hr, "Failed to determine length of value."); 186 ExitOnFailure(hr, "Failed to determine length of value.");
111 } 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 }
112 197
113 hr = vpEngine->FormatString(wzFormat, *psczOut, &cch); 198 hr = pEngine->FormatString(wzFormat, *psczOut, &cch);
114 if (E_MOREDATA == hr) 199 if (E_MOREDATA == hr)
115 { 200 {
116 ++cch; 201 ++cch;
@@ -118,7 +203,7 @@ DAPI_(HRESULT) BalFormatString(
118 hr = StrAllocSecure(psczOut, cch); 203 hr = StrAllocSecure(psczOut, cch);
119 ExitOnFailure(hr, "Failed to allocate value."); 204 ExitOnFailure(hr, "Failed to allocate value.");
120 205
121 hr = vpEngine->FormatString(wzFormat, *psczOut, &cch); 206 hr = pEngine->FormatString(wzFormat, *psczOut, &cch);
122 } 207 }
123 208
124LExit: 209LExit:
@@ -172,7 +257,7 @@ DAPI_(BOOL) BalVariableExists(
172 ) 257 )
173{ 258{
174 HRESULT hr = S_OK; 259 HRESULT hr = S_OK;
175 SIZE_T cch = 0; 260 BOOL fExists = FALSE;
176 261
177 if (!vpEngine) 262 if (!vpEngine)
178 { 263 {
@@ -180,9 +265,23 @@ DAPI_(BOOL) BalVariableExists(
180 ExitOnRootFailure(hr, "BalInitialize() must be called first."); 265 ExitOnRootFailure(hr, "BalInitialize() must be called first.");
181 } 266 }
182 267
183 hr = vpEngine->GetVariableString(wzVariable, NULL, &cch); 268 fExists = BalVariableExistsFromEngine(vpEngine, wzVariable);
184 269
185LExit: 270LExit:
271 return fExists;
272}
273
274
275DAPI_(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
186 return E_NOTFOUND != hr; 285 return E_NOTFOUND != hr;
187} 286}
188 287
@@ -194,7 +293,6 @@ DAPI_(HRESULT) BalGetStringVariable(
194 ) 293 )
195{ 294{
196 HRESULT hr = S_OK; 295 HRESULT hr = S_OK;
197 SIZE_T cch = 0;
198 296
199 if (!vpEngine) 297 if (!vpEngine)
200 { 298 {
@@ -202,13 +300,36 @@ DAPI_(HRESULT) BalGetStringVariable(
202 ExitOnRootFailure(hr, "BalInitialize() must be called first."); 300 ExitOnRootFailure(hr, "BalInitialize() must be called first.");
203 } 301 }
204 302
303 hr = BalGetStringVariableFromEngine(vpEngine, wzVariable, psczValue);
304
305LExit:
306 return hr;
307}
308
309
310// The contents of psczValue may be sensitive, if variable is hidden should keep value encrypted and SecureZeroFree.
311DAPI_(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
205 if (*psczValue) 320 if (*psczValue)
206 { 321 {
207 hr = StrMaxLength(*psczValue, &cch); 322 hr = StrMaxLength(*psczValue, &cch);
208 ExitOnFailure(hr, "Failed to determine length of value."); 323 ExitOnFailure(hr, "Failed to determine length of value.");
209 } 324 }
325 else
326 {
327 cch = VARIABLE_GROW_FACTOR;
328 hr = StrAlloc(psczValue, cch);
329 ExitOnFailure(hr, "Failed to pre-allocate value.");
330 }
210 331
211 hr = vpEngine->GetVariableString(wzVariable, *psczValue, &cch); 332 hr = pEngine->GetVariableString(wzVariable, *psczValue, &cch);
212 if (E_MOREDATA == hr) 333 if (E_MOREDATA == hr)
213 { 334 {
214 ++cch; 335 ++cch;
@@ -216,7 +337,7 @@ DAPI_(HRESULT) BalGetStringVariable(
216 hr = StrAllocSecure(psczValue, cch); 337 hr = StrAllocSecure(psczValue, cch);
217 ExitOnFailure(hr, "Failed to allocate value."); 338 ExitOnFailure(hr, "Failed to allocate value.");
218 339
219 hr = vpEngine->GetVariableString(wzVariable, *psczValue, &cch); 340 hr = pEngine->GetVariableString(wzVariable, *psczValue, &cch);
220 } 341 }
221 342
222LExit: 343LExit:
@@ -244,6 +365,82 @@ LExit:
244} 365}
245 366
246 367
368DAPI_(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
383LExit:
384 return hr;
385}
386
387
388DAPI_(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
420LExit:
421 return hr;
422}
423
424DAPI_(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
439LExit:
440 return hr;
441}
442
443
247DAPIV_(HRESULT) BalLog( 444DAPIV_(HRESULT) BalLog(
248 __in BOOTSTRAPPER_LOG_LEVEL level, 445 __in BOOTSTRAPPER_LOG_LEVEL level,
249 __in_z __format_string LPCSTR szFormat, 446 __in_z __format_string LPCSTR szFormat,
diff --git a/src/api/burn/balutil/inc/balutil.h b/src/api/burn/balutil/inc/balutil.h
index fad8a471..82fd1fe5 100644
--- a/src/api/burn/balutil/inc/balutil.h
+++ b/src/api/burn/balutil/inc/balutil.h
@@ -79,6 +79,27 @@ DAPI_(HRESULT) BalEvaluateCondition(
79 ); 79 );
80 80
81/******************************************************************* 81/*******************************************************************
82BalEscapeString - escapes a string to use as part of a formatted string variable.
83
84 Note: Use StrFree() to release psczOut.
85********************************************************************/
86DAPI_(HRESULT) BalEscapeString(
87 __in_z LPCWSTR wzIn,
88 __inout LPWSTR* psczOut
89 );
90
91/*******************************************************************
92BalEscapeStringFromEngine - escapes a string to use as part of a formatted string variable.
93
94 Note: Use StrFree() to release psczOut.
95********************************************************************/
96DAPI_(HRESULT) BalEscapeStringFromEngine(
97 __in IBootstrapperEngine* pEngine,
98 __in_z LPCWSTR wzIn,
99 __inout LPWSTR* psczOut
100 );
101
102/*******************************************************************
82BalFormatString - formats a string using variables in the engine. 103BalFormatString - formats a string using variables in the engine.
83 104
84 Note: Use StrFree() to release psczOut. 105 Note: Use StrFree() to release psczOut.
@@ -89,6 +110,17 @@ DAPI_(HRESULT) BalFormatString(
89 ); 110 );
90 111
91/******************************************************************* 112/*******************************************************************
113BalFormatStringFromEngine - formats a string using variables in the engine.
114
115 Note: Use StrFree() to release psczOut.
116********************************************************************/
117DAPI_(HRESULT) BalFormatStringFromEngine(
118 __in IBootstrapperEngine* pEngine,
119 __in_z LPCWSTR wzFormat,
120 __inout LPWSTR* psczOut
121 );
122
123/*******************************************************************
92BalGetNumericVariable - gets a number from a variable in the engine. 124BalGetNumericVariable - gets a number from a variable in the engine.
93 125
94 Note: Returns E_NOTFOUND if variable does not exist. 126 Note: Returns E_NOTFOUND if variable does not exist.
@@ -116,6 +148,15 @@ DAPI_(BOOL) BalVariableExists(
116 ); 148 );
117 149
118/******************************************************************* 150/*******************************************************************
151BalVariableExistsFromEngine - checks if a variable exists in the engine.
152
153********************************************************************/
154DAPI_(BOOL) BalVariableExistsFromEngine(
155 __in IBootstrapperEngine* pEngine,
156 __in_z LPCWSTR wzVariable
157 );
158
159/*******************************************************************
119BalGetStringVariable - gets a string from a variable in the engine. 160BalGetStringVariable - gets a string from a variable in the engine.
120 161
121 Note: Use StrFree() to release psczValue. 162 Note: Use StrFree() to release psczValue.
@@ -126,7 +167,19 @@ DAPI_(HRESULT) BalGetStringVariable(
126 ); 167 );
127 168
128/******************************************************************* 169/*******************************************************************
170BalGetStringVariableFromEngine - gets a string from a variable in the engine.
171
172 Note: Use StrFree() to release psczValue.
173********************************************************************/
174DAPI_(HRESULT) BalGetStringVariableFromEngine(
175 __in IBootstrapperEngine* pEngine,
176 __in_z LPCWSTR wzVariable,
177 __inout LPWSTR* psczValue
178 );
179
180/*******************************************************************
129BalSetStringVariable - sets a string variable in the engine. 181BalSetStringVariable - sets a string variable in the engine.
182 If the value contains unexpanded variables, set fFormatted to true.
130 183
131********************************************************************/ 184********************************************************************/
132DAPI_(HRESULT) BalSetStringVariable( 185DAPI_(HRESULT) BalSetStringVariable(
@@ -136,6 +189,36 @@ DAPI_(HRESULT) BalSetStringVariable(
136 ); 189 );
137 190
138/******************************************************************* 191/*******************************************************************
192BalGetVersionVariable - gets a version from a variable in the engine.
193
194 Note: Use StrFree() to release psczValue.
195********************************************************************/
196DAPI_(HRESULT) BalGetVersionVariable(
197 __in_z LPCWSTR wzVariable,
198 __inout LPWSTR* psczValue
199 );
200
201/*******************************************************************
202BalGetVersionVariableFromEngine - gets a version from a variable in the engine.
203
204 Note: Use StrFree() to release psczValue.
205********************************************************************/
206DAPI_(HRESULT) BalGetVersionVariableFromEngine(
207 __in IBootstrapperEngine* pEngine,
208 __in_z LPCWSTR wzVariable,
209 __inout LPWSTR* psczValue
210 );
211
212/*******************************************************************
213BalSetVersionVariable - sets a version variable in the engine.
214
215********************************************************************/
216DAPI_(HRESULT) BalSetVersionVariable(
217 __in_z LPCWSTR wzVariable,
218 __in_z_opt LPCWSTR wzValue
219 );
220
221/*******************************************************************
139 BalLog - logs a message with the engine. 222 BalLog - logs a message with the engine.
140 223
141********************************************************************/ 224********************************************************************/
diff --git a/src/api/burn/balutil/precomp.h b/src/api/burn/balutil/precomp.h
index c500060a..207c8ca6 100644
--- a/src/api/burn/balutil/precomp.h
+++ b/src/api/burn/balutil/precomp.h
@@ -7,6 +7,7 @@
7#include <msi.h> 7#include <msi.h>
8#include <wininet.h> 8#include <wininet.h>
9#include <CommCtrl.h> 9#include <CommCtrl.h>
10#include <strsafe.h>
10 11
11#include <dutil.h> 12#include <dutil.h>
12#include <pathutil.h> 13#include <pathutil.h>
diff --git a/src/api/burn/mbanative/mbanative.def b/src/api/burn/mbanative/mbanative.def
index 28e923b6..4bad14d0 100644
--- a/src/api/burn/mbanative/mbanative.def
+++ b/src/api/burn/mbanative/mbanative.def
@@ -2,8 +2,14 @@
2 2
3 3
4EXPORTS 4EXPORTS
5 BalEscapeStringFromEngine
6 BalFormatStringFromEngine
7 BalGetStringVariableFromEngine
8 BalGetVersionVariableFromEngine
9 BalVariableExistsFromEngine
5 InitializeFromCreateArgs 10 InitializeFromCreateArgs
6 StoreBAInCreateResults 11 StoreBAInCreateResults
12 StrFree
7 VerCompareParsedVersions 13 VerCompareParsedVersions
8 VerCompareStringVersions 14 VerCompareStringVersions
9 VerCopyVersion 15 VerCopyVersion