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;
}
}
}