aboutsummaryrefslogtreecommitdiff
path: root/src/api/burn/WixToolset.Mba.Core
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 /src/api/burn/WixToolset.Mba.Core
parent27c6decae94536cae338731b6cb765aa92776486 (diff)
downloadwix-a645cabc7a46adaa8f26d913bbb3cc5f9cd07820.tar.gz
wix-a645cabc7a46adaa8f26d913bbb3cc5f9cd07820.tar.bz2
wix-a645cabc7a46adaa8f26d913bbb3cc5f9cd07820.zip
Use balutil methods in Engine.cs to avoid size_t ugliness.
Diffstat (limited to 'src/api/burn/WixToolset.Mba.Core')
-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
7 files changed, 171 insertions, 193 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);