using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Runtime.InteropServices;
using System.Security;
using Vanara.Extensions;
using Vanara.PInvoke;
namespace Vanara.InteropServices
{
/// Unmanaged memory methods for COM.
///
public sealed class CoTaskMemoryMethods : IMemoryMethods
{
/// Gets a value indicating whether this memory supports locking.
/// if lockable; otherwise, .
bool ISimpleMemoryMethods.Lockable => false;
/// Static instance to methods.
public static IMemoryMethods Instance { get; } = new CoTaskMemoryMethods();
/// Gets a handle to a memory allocation of the specified size.
/// The size, in bytes, of memory to allocate.
/// A memory handle.
public IntPtr AllocMem(int size) => Marshal.AllocCoTaskMem(size);
/// Gets the Ansi allocation method.
/// The secure string.
/// A memory handle.
public IntPtr AllocSecureStringAnsi(SecureString secureString) => Marshal.SecureStringToCoTaskMemAnsi(secureString);
/// Gets the Unicode allocation method.
/// The secure string.
/// A memory handle.
public IntPtr AllocSecureStringUni(SecureString secureString) => Marshal.SecureStringToCoTaskMemUnicode(secureString);
/// Gets the Ansi string allocation method.
/// The value.
/// A memory handle.
public IntPtr AllocStringAnsi(string value) => Marshal.StringToCoTaskMemAnsi(value);
/// Gets the Unicode string allocation method.
/// The value.
/// A memory handle.
public IntPtr AllocStringUni(string value) => Marshal.StringToCoTaskMemUni(value);
/// Frees the memory associated with a handle.
/// A memory handle.
public void FreeMem(IntPtr hMem) => Marshal.FreeCoTaskMem(hMem);
/// Gets the Ansi free method.
/// A memory handle.
public void FreeSecureStringAnsi(IntPtr hMem) => Marshal.ZeroFreeCoTaskMemAnsi(hMem);
/// Gets the Unicode free method.
/// A memory handle.
public void FreeSecureStringUni(IntPtr hMem) => Marshal.ZeroFreeCoTaskMemUnicode(hMem);
/// Locks the memory of a specified handle and gets a pointer to it.
/// A memory handle.
/// A pointer to the locked memory.
public IntPtr LockMem(IntPtr hMem) => hMem;
/// Gets the reallocation method.
/// A memory handle.
/// The size, in bytes, of memory to allocate.
/// A memory handle.
public IntPtr ReAllocMem(IntPtr hMem, int size) => Marshal.ReAllocCoTaskMem(hMem, size);
/// Unlocks the memory of a specified handle.
/// A memory handle.
/// if the memory object is still locked after decrementing the lock count; otherwise .
public bool UnlockMem(IntPtr hMem) => false;
}
/// A for memory allocated via COM.
///
public class SafeCoTaskMemHandle : SafeMemoryHandleExt
{
/// Initializes a new instance of the class.
/// The handle.
/// The size of memory allocated to the handle, in bytes.
/// if set to true if this class is responsible for freeing the memory on disposal.
public SafeCoTaskMemHandle(IntPtr handle, SizeT size, bool ownsHandle = true) : base(handle, size, ownsHandle) { }
/// Initializes a new instance of the class.
/// The size of memory to allocate, in bytes.
/// size - The value of this argument must be non-negative
public SafeCoTaskMemHandle(SizeT size) : base(size) { }
///
/// Allocates from unmanaged memory to represent an array of pointers and marshals the unmanaged pointers (IntPtr) to the native
/// array equivalent.
///
/// Array of unmanaged pointers
/// SafeCoTaskMemHandle object to an native (unmanaged) array of pointers
public SafeCoTaskMemHandle(byte[] bytes) : base(bytes) { }
///
/// Allocates from unmanaged memory to represent an array of pointers and marshals the unmanaged pointers (IntPtr) to the native
/// array equivalent.
///
/// Array of unmanaged pointers
/// SafeCoTaskMemHandle object to an native (unmanaged) array of pointers
public SafeCoTaskMemHandle(IntPtr[] values) : base(values) { }
/// Allocates from unmanaged memory to represent a Unicode string (WSTR) and marshal this to a native PWSTR.
/// The string value.
/// SafeCoTaskMemHandle object to an native (unmanaged) Unicode string
public SafeCoTaskMemHandle(string s) : base(s) { }
/// Initializes a new instance of the class.
[ExcludeFromCodeCoverage]
internal SafeCoTaskMemHandle() : base(0) { }
/// Represents a NULL memory pointer.
public static SafeCoTaskMemHandle Null => new(IntPtr.Zero, 0, false);
///
/// Allocates from unmanaged memory to represent a structure with a variable length array at the end and marshal these structure
/// elements. It is the callers responsibility to marshal what precedes the trailing array into the unmanaged memory. ONLY
/// structures with attribute StructLayout of LayoutKind.Sequential are supported.
///
/// Type of the trailing array of structures
/// Collection of structure objects
///
/// Number of items in . Setting this value to -1 will cause the method to get the count by iterating
/// through .
///
/// Number of bytes preceding the trailing array of structures
/// object to an native (unmanaged) structure with a trail array of structures
public static SafeCoTaskMemHandle CreateFromList(IEnumerable values, int count = -1, int prefixBytes = 0) =>
new(InteropExtensions.MarshalToPtr(count < 0 ? values : values.Take(count), mm.AllocMem, out int s, prefixBytes), s);
/// Allocates from unmanaged memory sufficient memory to hold an array of strings.
/// The list of strings.
/// The packing type for the strings.
/// The character set to use for the strings.
/// Number of bytes preceding the trailing strings.
///
/// object to an native (unmanaged) array of strings stored using the
/// model and the character set defined by .
///
public static SafeCoTaskMemHandle CreateFromStringList(IEnumerable values, StringListPackMethod packing = StringListPackMethod.Concatenated,
CharSet charSet = CharSet.Auto, int prefixBytes = 0) => new(InteropExtensions.MarshalToPtr(values, packing, mm.AllocMem, out int s, charSet, prefixBytes), s);
/// Allocates from unmanaged memory sufficient memory to hold an object of type T.
/// Native type
/// The value.
/// object to an native (unmanaged) memory block the size of T.
public static SafeCoTaskMemHandle CreateFromStructure(in T value = default) => new(InteropExtensions.MarshalToPtr(value, mm.AllocMem, out int s), s);
/// Converts an to a where it owns the reference.
/// The .
/// The result of the conversion.
public static implicit operator SafeCoTaskMemHandle(IntPtr ptr) => new(ptr, 0, true);
}
}