using Microsoft.Win32.SafeHandles; using System; using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; using System.Security; using Vanara.Extensions; namespace Vanara.InteropServices { /// Safely handles an unmanaged memory allocated Unicode string. /// public class SafeCoTaskMemString : SafeHandleZeroOrMinusOneIsInvalid { private readonly CharSet chSet = CharSet.Unicode; /// Initializes a new instance of the class. /// The string value. /// The character set. /// true to reliably release the handle during finalization; false to prevent it. public SafeCoTaskMemString(string s, CharSet charSet = CharSet.Unicode, bool ownsHandle = true) : this(StringHelper.AllocString(s, charSet), charSet, ownsHandle) { Capacity = StringHelper.GetByteCount(s, true, charSet); } /// Initializes a new instance of the class. /// The string value. /// The character set. public SafeCoTaskMemString(SecureString s, CharSet charSet = CharSet.Unicode) : this(StringHelper.AllocSecureString(s, charSet), charSet) { Capacity = s == null ? 0 : StringHelper.GetCharSize(charSet) * (s.Length + 1); } /// Initializes a new instance of the class. /// The size of the buffer in characters, including the null character terminator. /// The character set. public SafeCoTaskMemString(int charLen, CharSet charSet = CharSet.Unicode) : this(StringHelper.AllocChars((uint)charLen, charSet), charSet) { Capacity = charLen * StringHelper.GetCharSize(charSet); } /// Prevents a default instance of the class from being created. [ExcludeFromCodeCoverage] private SafeCoTaskMemString() : base(true) { } /// Initializes a new instance of the class. /// The PTR. /// The character set. /// true to reliably release the handle during finalization; false to prevent it. [ExcludeFromCodeCoverage] private SafeCoTaskMemString(IntPtr ptr, CharSet charSet = CharSet.Unicode, bool ownsHandle = true) : base(ownsHandle) { chSet = charSet; SetHandle(ptr); } /// Represents a null value. Used primarily for comparrison. /// A null value. public static SafeCoTaskMemString Null => new SafeCoTaskMemString(IntPtr.Zero, CharSet.Unicode, false); /// Gets the number of allocated bytes or -1 if the size is unknown (for example if it is holding a . /// The number of allocated bytes. public int Capacity { get; } = -1; /// Gets the number of allocated characters or -1 if the size is unknown (for example if it is holding a . /// The number of characters bytes. public int CharCapacity => Capacity == -1 ? -1 : Capacity / StringHelper.GetCharSize(chSet); /// Returns the value of the field. /// The instance. /// /// An representing the value of the handle field. If the handle has been marked invalid with /// , this method still returns the original handle value, which can be a stale value. /// public static explicit operator IntPtr(SafeCoTaskMemString s) => s.DangerousGetHandle(); /// Returns the string value held by a . /// The instance. /// A value held by the or null if the handle or value is invalid. public static implicit operator string(SafeCoTaskMemString s) => s?.ToString(); /// Returns the string value held by this instance. /// A value held by this instance or null if the handle is invalid. public override string ToString() => IsInvalid ? null : StringHelper.GetString(handle, chSet); /// When overridden in a derived class, executes the code required to free the handle. /// /// true if the handle is released successfully; otherwise, in the event of a catastrophic failure, false. In this case, it generates a /// releaseHandleFailed MDA Managed Debugging Assistant. /// protected override bool ReleaseHandle() { StringHelper.FreeString(handle, chSet); return true; } } }