using System; using System.Linq; using System.Runtime.InteropServices; using Vanara.Extensions; namespace Vanara.InteropServices { /// Marshals an array of strings to a concatenated list of strings with an extra NULL terminator. /// public class NullTermStringArrayMarshaler : ICustomMarshaler { private readonly CharSet charSet = CharSet.Unicode; private int memSize = 0; private NullTermStringArrayMarshaler(string cookie) { if (string.IsNullOrEmpty(cookie)) return; try { charSet = (CharSet)Enum.Parse(typeof(CharSet), cookie, true); } catch { } } /// Gets the instance. /// The cookie. /// A new instance of this class. public static ICustomMarshaler GetInstance(string cookie) => new NullTermStringArrayMarshaler(cookie); /// void ICustomMarshaler.CleanUpManagedData(object ManagedObj) { } /// void ICustomMarshaler.CleanUpNativeData(IntPtr pNativeData) => Marshal.FreeCoTaskMem(pNativeData); /// int ICustomMarshaler.GetNativeDataSize() => memSize; /// IntPtr ICustomMarshaler.MarshalManagedToNative(object ManagedObj) { if (ManagedObj == null) return IntPtr.Zero; string[] sa = null; if (ManagedObj is string s) sa = new string[] { s }; if (ManagedObj is string[] _sa) sa = _sa; if (sa == null) throw new InvalidOperationException($"{nameof(NullTermStringArrayMarshaler)} can only marshal object types of {typeof(string)} or {typeof(string[])}."); return sa.MarshalToPtr(InteropServices.StringListPackMethod.Concatenated, Marshal.AllocCoTaskMem, out memSize, charSet); } /// object ICustomMarshaler.MarshalNativeToManaged(IntPtr pNativeData) => pNativeData.ToStringEnum(charSet).ToArray(); } }