using System;
using System.Runtime.InteropServices;
using Vanara.Extensions;
using Vanara.InteropServices;
using static Vanara.PInvoke.Ole32;

namespace Vanara.PInvoke
{
	public static partial class OleAut32
	{
		/// <summary>SafeArray advanced features.</summary>
		[Flags]
		[PInvokeData("OAIdl.h", MSDNShortId = "cc237824")]
		public enum ADVFEATUREFLAGS : ushort
		{
			/// <summary>An array that is allocated on the stack.</summary>
			FADF_AUTO = 0x0001,

			/// <summary>An array that is statically allocated.</summary>
			FADF_STATIC = 0x0002,

			/// <summary>An array that is embedded in a structure.</summary>
			FADF_EMBEDDED = 0x0004,

			/// <summary>An array that may not be resized or reallocated.</summary>
			FADF_FIXEDSIZE = 0x0010,

			/// <summary>
			/// An array that contains records. When set, there will be a pointer to the IRecordInfo interface at negative offset 4 in the
			/// array descriptor.
			/// </summary>
			FADF_RECORD = 0x0020,

			/// <summary>
			/// An array that has an IID identifying interface. When set, there will be a GUID at negative offset 16 in the safe array
			/// descriptor. Flag is set only when FADF_DISPATCH or FADF_UNKNOWN is also set.
			/// </summary>
			FADF_HAVEIID = 0x0040,

			/// <summary>An array that has a variant type. The variant type can be retrieved with SafeArrayGetVartype.</summary>
			FADF_HAVEVARTYPE = 0x0080,

			/// <summary>An array of BSTRs.</summary>
			FADF_BSTR = 0x0100,

			/// <summary>An array of IUnknown*.</summary>
			FADF_UNKNOWN = 0x0200,

			/// <summary>An array of IDispatch*.</summary>
			FADF_DISPATCH = 0x0400,

			/// <summary>An array of VARIANTs.</summary>
			FADF_VARIANT = 0x0800
		}

		/// <summary>
		/// <para>Increments the lock count of an array, and retrieves a pointer to the array data.</para>
		/// </summary>
		/// <param name="psa">
		/// <para>An array descriptor created by SafeArrayCreate.</para>
		/// </param>
		/// <param name="ppvData">
		/// <para>The array data.</para>
		/// </param>
		/// <returns>
		/// <para>This function can return one of these values.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Return code</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>S_OK</term>
		/// <term>Success.</term>
		/// </item>
		/// <item>
		/// <term>E_INVALIDARG</term>
		/// <term>The argument psa is not valid.</term>
		/// </item>
		/// <item>
		/// <term>E_UNEXPECTED</term>
		/// <term>The array could not be locked.</term>
		/// </item>
		/// </list>
		/// </returns>
		/// <remarks>
		/// <para>After calling <c>SafeArrayAccessData</c>, you must call the SafeArrayUnaccessData function to unlock the array.</para>
		/// <para>Examples</para>
		/// <para>
		/// The following example sorts a safe array of one dimension that contains BSTRs by accessing the array elements directly. This
		/// approach is faster than using SafeArrayGetElement and SafeArrayPutElement.
		/// </para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/desktop/api/oleauto/nf-oleauto-safearrayaccessdata HRESULT SafeArrayAccessData( SAFEARRAY
		// *psa, void HUGEP **ppvData );
		[DllImport(Lib.OleAut32, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("oleauto.h", MSDNShortId = "ded2112e-f6cd-4982-bacb-b95370e80187")]
		public static extern HRESULT SafeArrayAccessData(SafeSAFEARRAY psa, out IntPtr ppvData);

		/// <summary>
		/// <para>
		/// The safe array for which the pinning reference count of the descriptor should increase. While that count remains greater than 0,
		/// the memory for the descriptor is prevented from being freed by calls to the SafeArrayDestroy or SafeArrayDestroyDescriptor functions.
		/// </para>
		/// <para>
		/// Returns the safe array data for which a pinning reference was added, if <c>SafeArrayAddRef</c> also added a pinning reference for
		/// the safe array data. This parameter is NULL if <c>SafeArrayAddRef</c> did not add a pinning reference for the safe array data.
		/// <c>SafeArrayAddRef</c> does not add a pinning reference for the safe array data if that safe array data was not dynamically allocated.
		/// </para>
		/// </summary>
		/// <param name="psa">
		/// <para>
		/// The safe array for which the pinning reference count of the descriptor should increase. While that count remains greater than 0,
		/// the memory for the descriptor is prevented from being freed by calls to the SafeArrayDestroy or SafeArrayDestroyDescriptor functions.
		/// </para>
		/// </param>
		/// <param name="ppDataToRelease">
		/// <para>
		/// Returns the safe array data for which a pinning reference was added, if <c>SafeArrayAddRef</c> also added a pinning reference for
		/// the safe array data. This parameter is NULL if <c>SafeArrayAddRef</c> did not add a pinning reference for the safe array data.
		/// <c>SafeArrayAddRef</c> does not add a pinning reference for the safe array data if that safe array data was not dynamically allocated.
		/// </para>
		/// </param>
		/// <returns>
		/// <para>If this function succeeds, it returns <c>S_OK</c>. Otherwise, it returns an <c>HRESULT</c> error code.</para>
		/// </returns>
		/// <remarks>
		/// <para>
		/// Safe arrays have not traditionally had a reference count. All existing usage of safe arrays will continue to work with no
		/// changes. The <c>SafeArrayAddRef</c>, SafeArrayReleaseData, SafeArrayReleaseDescriptor functions add the ability to use reference
		/// counting to pin the safe array into memory before calling from an untrusted script into an IDispatch method that may not expect
		/// the script to free that memory before the method returns, so that the script cannot force the code for that method into accessing
		/// memory that has been freed. After such a method safely returns, the pinning references should be released. You can release the
		/// pinning references by calling the following functions:
		/// </para>
		/// <list type="bullet">
		/// <item>
		/// <term>SafeArrayReleaseData, for the data that the ppDataToRelease parameter points to, if it is not null.</term>
		/// </item>
		/// <item>
		/// <term>SafeArrayReleaseDescriptor, for the descriptor that the psa parameter specifies.</term>
		/// </item>
		/// </list>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/desktop/api/oleauto/nf-oleauto-safearrayaddref HRESULT SafeArrayAddRef( SAFEARRAY *psa,
		// PVOID *ppDataToRelease );
		[DllImport(Lib.OleAut32, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("oleauto.h", MSDNShortId = "0745D2E7-447E-4688-ADCF-1F889BC55BFB")]
		public static extern HRESULT SafeArrayAddRef(SafeSAFEARRAY psa, out IntPtr ppDataToRelease);

		/// <summary>
		/// <para>Allocates memory for a safe array, based on a descriptor created with SafeArrayAllocDescriptor.</para>
		/// </summary>
		/// <param name="psa">
		/// <para>A safe array descriptor created by SafeArrayAllocDescriptor.</para>
		/// </param>
		/// <returns>
		/// <para>This function can return one of these values.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Return code</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>S_OK</term>
		/// <term>Success.</term>
		/// </item>
		/// <item>
		/// <term>E_INVALIDARG</term>
		/// <term>The argument psa is not valid.</term>
		/// </item>
		/// <item>
		/// <term>E_UNEXPECTED</term>
		/// <term>The array could not be locked.</term>
		/// </item>
		/// </list>
		/// </returns>
		// https://docs.microsoft.com/en-us/windows/desktop/api/oleauto/nf-oleauto-safearrayallocdata HRESULT SafeArrayAllocData( SAFEARRAY
		// *psa );
		[DllImport(Lib.OleAut32, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("oleauto.h", MSDNShortId = "a1f984cd-9638-415d-8582-25b1bdfbd694")]
		public static extern HRESULT SafeArrayAllocData(SafeSAFEARRAY psa);

		/// <summary>
		/// <para>Allocates memory for a safe array descriptor.</para>
		/// </summary>
		/// <param name="cDims">
		/// <para>The number of dimensions of the array.</para>
		/// </param>
		/// <param name="ppsaOut">
		/// <para>The safe array descriptor.</para>
		/// </param>
		/// <returns>
		/// <para>This function can return one of these values.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Return code</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>S_OK</term>
		/// <term>Success.</term>
		/// </item>
		/// <item>
		/// <term>E_INVALIDARG</term>
		/// <term>The argument psa was not valid.</term>
		/// </item>
		/// <item>
		/// <term>E_UNEXPECTED</term>
		/// <term>The array could not be locked.</term>
		/// </item>
		/// </list>
		/// </returns>
		/// <remarks>
		/// <para>
		/// This function allows the creation of safe arrays that contain elements with data types other than those provided by
		/// SafeArrayCreate. After creating an array descriptor using <c>SafeArrayAllocDescriptor</c>, set the element size in the array
		/// descriptor, an call SafeArrayAllocData to allocate memory for the array elements.
		/// </para>
		/// <para>Examples</para>
		/// <para>The following example creates a safe array using the <c>SafeArrayAllocDescriptor</c> and SafeArrayAllocData functions.</para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/desktop/api/oleauto/nf-oleauto-safearrayallocdescriptor HRESULT SafeArrayAllocDescriptor(
		// UINT cDims, SAFEARRAY **ppsaOut );
		[DllImport(Lib.OleAut32, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("oleauto.h", MSDNShortId = "8fe5c802-cdc0-4e7a-9410-ba65f9a5140e")]
		public static extern HRESULT SafeArrayAllocDescriptor(uint cDims, out SafeDescriptorSAFEARRAY ppsaOut);

		/// <summary>
		/// <para>
		/// Creates a safe array descriptor for an array of any valid variant type, including VT_RECORD, without allocating the array data.
		/// </para>
		/// </summary>
		/// <param name="vt">
		/// <para>The variant type.</para>
		/// </param>
		/// <param name="cDims">
		/// <para>The number of dimensions in the array.</para>
		/// </param>
		/// <param name="ppsaOut">
		/// <para>The safe array descriptor.</para>
		/// </param>
		/// <returns>
		/// <para>This function can return one of these values.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Return code</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>S_OK</term>
		/// <term>Success.</term>
		/// </item>
		/// <item>
		/// <term>E_INVALIDARG</term>
		/// <term>The argument psa was not valid.</term>
		/// </item>
		/// </list>
		/// </returns>
		/// <remarks>
		/// <para>
		/// Because SafeArrayAllocDescriptor does not take a VARTYPE, it is not possible to use it to create the safe array descriptor for an
		/// array of records. The <c>SafeArrayAllocDescriptorEx</c> is used to allocate a safe array descriptor for an array of records of
		/// the given dimensions.
		/// </para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/desktop/api/oleauto/nf-oleauto-safearrayallocdescriptorex HRESULT
		// SafeArrayAllocDescriptorEx( VARTYPE vt, UINT cDims, SAFEARRAY **ppsaOut );
		[DllImport(Lib.OleAut32, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("oleauto.h", MSDNShortId = "c368d278-ef62-4cf3-a7f8-c48549207c09")]
		public static extern HRESULT SafeArrayAllocDescriptorEx(VARTYPE vt, uint cDims, out SafeDescriptorSAFEARRAY ppsaOut);

		/// <summary>
		/// <para>Creates a copy of an existing safe array.</para>
		/// </summary>
		/// <param name="psa">
		/// <para>A safe array descriptor created by SafeArrayCreate.</para>
		/// </param>
		/// <param name="ppsaOut">
		/// <para>The safe array descriptor.</para>
		/// </param>
		/// <returns>
		/// <para>This function can return one of these values.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Return code</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>S_OK</term>
		/// <term>Success.</term>
		/// </item>
		/// <item>
		/// <term>E_INVALIDARG</term>
		/// <term>The argument psa was not valid.</term>
		/// </item>
		/// <item>
		/// <term>E_OUTOFMEMORY</term>
		/// <term>Insufficient memory to complete the operation.</term>
		/// </item>
		/// </list>
		/// </returns>
		/// <remarks>
		/// <para>
		/// <c>SafeArrayCopy</c> calls the string or variant manipulation functions if the array to copy contains either of these data types.
		/// If the array being copied contains object references, the reference counts for the objects are incremented.
		/// </para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/desktop/api/oleauto/nf-oleauto-safearraycopy HRESULT SafeArrayCopy( SAFEARRAY *psa,
		// SAFEARRAY **ppsaOut );
		[DllImport(Lib.OleAut32, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("oleauto.h", MSDNShortId = "8f84d4f6-1852-4ad8-b174-f3fa37e5bbd6")]
		public static extern HRESULT SafeArrayCopy(SafeSAFEARRAY psa, out SafeSAFEARRAY ppsaOut);

		/// <summary>
		/// <para>
		/// Copies the source array to the specified target array after releasing any resources in the target array. This is similar to
		/// SafeArrayCopy, except that the target array has to be set up by the caller. The target is not allocated or reallocated.
		/// </para>
		/// </summary>
		/// <param name="psaSource">
		/// <para>The safe array to copy.</para>
		/// </param>
		/// <param name="psaTarget">
		/// <para>The target safe array.</para>
		/// </param>
		/// <returns>
		/// <para>This function can return one of these values.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Return code</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>S_OK</term>
		/// <term>Success.</term>
		/// </item>
		/// <item>
		/// <term>E_INVALIDARG</term>
		/// <term>The argument psa was not valid.</term>
		/// </item>
		/// <item>
		/// <term>E_OUTOFMEMORY</term>
		/// <term>Insufficient memory to complete the operation.</term>
		/// </item>
		/// </list>
		/// </returns>
		// https://docs.microsoft.com/en-us/windows/desktop/api/oleauto/nf-oleauto-safearraycopydata HRESULT SafeArrayCopyData( SAFEARRAY
		// *psaSource, SAFEARRAY *psaTarget );
		[DllImport(Lib.OleAut32, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("oleauto.h", MSDNShortId = "32c1fc4f-3fe0-490f-b5af-640514a8cecc")]
		public static extern HRESULT SafeArrayCopyData(SafeSAFEARRAY psaSource, SafeSAFEARRAY psaTarget);

		/// <summary>
		/// <para>
		/// Creates a new array descriptor, allocates and initializes the data for the array, and returns a pointer to the new array descriptor.
		/// </para>
		/// </summary>
		/// <param name="vt">
		/// <para>
		/// The base type of the array (the VARTYPE of each element of the array). The VARTYPE is restricted to a subset of the variant
		/// types. Neither the VT_ARRAY nor the VT_BYREF flag can be set. VT_EMPTY and VT_NULL are not valid base types for the array. All
		/// other types are legal.
		/// </para>
		/// </param>
		/// <param name="cDims">
		/// <para>The number of dimensions in the array. The number cannot be changed after the array is created.</para>
		/// </param>
		/// <param name="rgsabound">
		/// <para>A vector of bounds (one for each dimension) to allocate for the array.</para>
		/// </param>
		/// <returns>
		/// <para>A safe array descriptor, or null if the array could not be created.</para>
		/// </returns>
		// https://docs.microsoft.com/en-us/windows/desktop/api/oleauto/nf-oleauto-safearraycreate SAFEARRAY * SafeArrayCreate( VARTYPE vt,
		// UINT cDims, SAFEARRAYBOUND *rgsabound );
		[DllImport(Lib.OleAut32, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("oleauto.h", MSDNShortId = "5b94f1a2-a558-473f-85dd-9545c0464cc7")]
		public static extern SafeSAFEARRAY SafeArrayCreate(VARTYPE vt, uint cDims, in SAFEARRAYBOUND rgsabound);

		/// <summary>
		/// <para>Creates and returns a safe array descriptor from the specified VARTYPE, number of dimensions and bounds.</para>
		/// </summary>
		/// <param name="vt">
		/// <para>
		/// The base type or the VARTYPE of each element of the array. The FADF_RECORD flag can be set for a variant type VT_RECORD, The
		/// FADF_HAVEIID flag can be set for VT_DISPATCH or VT_UNKNOWN, and FADF_HAVEVARTYPE can be set for all other VARTYPEs.
		/// </para>
		/// </param>
		/// <param name="cDims">
		/// <para>The number of dimensions in the array.</para>
		/// </param>
		/// <param name="rgsabound">
		/// <para>A vector of bounds (one for each dimension) to allocate for the array.</para>
		/// </param>
		/// <param name="pvExtra">
		/// <para>
		/// the type information of the user-defined type, if you are creating a safe array of user-defined types. If the vt parameter is
		/// VT_RECORD, then pvExtra will be a pointer to an IRecordInfo describing the record. If the vt parameter is VT_DISPATCH or
		/// VT_UNKNOWN, then pvExtra will contain a pointer to a GUID representing the type of interface being passed to the array.
		/// </para>
		/// </param>
		/// <returns>
		/// <para>A safe array descriptor, or null if the array could not be created.</para>
		/// </returns>
		/// <remarks>
		/// <para>
		/// If the VARTYPE is VT_RECORD then SafeArraySetRecordInfo is called. If the VARTYPE is VT_DISPATCH or VT_UNKNOWN then the elements
		/// of the array must contain interfaces of the same type. Part of the process of marshaling this array to other processes does
		/// include generating the proxy/stub code of the IID pointed to by the pvExtra parameter. To actually pass heterogeneous interfaces
		/// one will need to specify either IID_IUnknown or IID_IDispatch in pvExtra and provide some other means for the caller to identify
		/// how to query for the actual interface.
		/// </para>
		/// <para>Examples</para>
		/// <para>The following example describes how a safe array of user-defined types is stored into a variant of type VT_RECORD.</para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/desktop/api/oleauto/nf-oleauto-safearraycreateex SAFEARRAY * SafeArrayCreateEx( VARTYPE
		// vt, UINT cDims, SAFEARRAYBOUND *rgsabound, PVOID pvExtra );
		[DllImport(Lib.OleAut32, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("oleauto.h", MSDNShortId = "63117428-6676-4fb5-a0ae-7e3b22546d77")]
		// public static extern SAFEARRAY * SafeArrayCreateEx(VARTYPE vt, uint cDims, ref SAFEARRAYBOUND rgsabound, IntPtr pvExtra);
		public static extern SafeSAFEARRAY SafeArrayCreateEx(VARTYPE vt, uint cDims, in SAFEARRAYBOUND rgsabound, IntPtr pvExtra);

		/// <summary>
		/// <para>Creates and returns a safe array descriptor from the specified VARTYPE, number of dimensions and bounds.</para>
		/// </summary>
		/// <param name="vt">
		/// <para>
		/// The base type or the VARTYPE of each element of the array. The FADF_RECORD flag can be set for a variant type VT_RECORD, The
		/// FADF_HAVEIID flag can be set for VT_DISPATCH or VT_UNKNOWN, and FADF_HAVEVARTYPE can be set for all other VARTYPEs.
		/// </para>
		/// </param>
		/// <param name="cDims">
		/// <para>The number of dimensions in the array.</para>
		/// </param>
		/// <param name="rgsabound">
		/// <para>A vector of bounds (one for each dimension) to allocate for the array.</para>
		/// </param>
		/// <param name="pvExtra">
		/// <para>
		/// the type information of the user-defined type, if you are creating a safe array of user-defined types. If the vt parameter is
		/// VT_RECORD, then pvExtra will be a pointer to an IRecordInfo describing the record. If the vt parameter is VT_DISPATCH or
		/// VT_UNKNOWN, then pvExtra will contain a pointer to a GUID representing the type of interface being passed to the array.
		/// </para>
		/// </param>
		/// <returns>
		/// <para>A safe array descriptor, or null if the array could not be created.</para>
		/// </returns>
		/// <remarks>
		/// <para>
		/// If the VARTYPE is VT_RECORD then SafeArraySetRecordInfo is called. If the VARTYPE is VT_DISPATCH or VT_UNKNOWN then the elements
		/// of the array must contain interfaces of the same type. Part of the process of marshaling this array to other processes does
		/// include generating the proxy/stub code of the IID pointed to by the pvExtra parameter. To actually pass heterogeneous interfaces
		/// one will need to specify either IID_IUnknown or IID_IDispatch in pvExtra and provide some other means for the caller to identify
		/// how to query for the actual interface.
		/// </para>
		/// <para>Examples</para>
		/// <para>The following example describes how a safe array of user-defined types is stored into a variant of type VT_RECORD.</para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/desktop/api/oleauto/nf-oleauto-safearraycreateex SAFEARRAY * SafeArrayCreateEx( VARTYPE
		// vt, UINT cDims, SAFEARRAYBOUND *rgsabound, PVOID pvExtra );
		[DllImport(Lib.OleAut32, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("oleauto.h", MSDNShortId = "63117428-6676-4fb5-a0ae-7e3b22546d77")]
		// public static extern SAFEARRAY * SafeArrayCreateEx(VARTYPE vt, uint cDims, ref SAFEARRAYBOUND rgsabound, IntPtr pvExtra);
		public static extern SafeSAFEARRAY SafeArrayCreateEx(VARTYPE vt, uint cDims, in SAFEARRAYBOUND rgsabound, IRecordInfo pvExtra);

		/// <summary>
		/// <para>Creates and returns a safe array descriptor from the specified VARTYPE, number of dimensions and bounds.</para>
		/// </summary>
		/// <param name="vt">
		/// <para>
		/// The base type or the VARTYPE of each element of the array. The FADF_RECORD flag can be set for a variant type VT_RECORD, The
		/// FADF_HAVEIID flag can be set for VT_DISPATCH or VT_UNKNOWN, and FADF_HAVEVARTYPE can be set for all other VARTYPEs.
		/// </para>
		/// </param>
		/// <param name="cDims">
		/// <para>The number of dimensions in the array.</para>
		/// </param>
		/// <param name="rgsabound">
		/// <para>A vector of bounds (one for each dimension) to allocate for the array.</para>
		/// </param>
		/// <param name="pvExtra">
		/// <para>
		/// the type information of the user-defined type, if you are creating a safe array of user-defined types. If the vt parameter is
		/// VT_RECORD, then pvExtra will be a pointer to an IRecordInfo describing the record. If the vt parameter is VT_DISPATCH or
		/// VT_UNKNOWN, then pvExtra will contain a pointer to a GUID representing the type of interface being passed to the array.
		/// </para>
		/// </param>
		/// <returns>
		/// <para>A safe array descriptor, or null if the array could not be created.</para>
		/// </returns>
		/// <remarks>
		/// <para>
		/// If the VARTYPE is VT_RECORD then SafeArraySetRecordInfo is called. If the VARTYPE is VT_DISPATCH or VT_UNKNOWN then the elements
		/// of the array must contain interfaces of the same type. Part of the process of marshaling this array to other processes does
		/// include generating the proxy/stub code of the IID pointed to by the pvExtra parameter. To actually pass heterogeneous interfaces
		/// one will need to specify either IID_IUnknown or IID_IDispatch in pvExtra and provide some other means for the caller to identify
		/// how to query for the actual interface.
		/// </para>
		/// <para>Examples</para>
		/// <para>The following example describes how a safe array of user-defined types is stored into a variant of type VT_RECORD.</para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/desktop/api/oleauto/nf-oleauto-safearraycreateex SAFEARRAY * SafeArrayCreateEx( VARTYPE
		// vt, UINT cDims, SAFEARRAYBOUND *rgsabound, PVOID pvExtra );
		[DllImport(Lib.OleAut32, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("oleauto.h", MSDNShortId = "63117428-6676-4fb5-a0ae-7e3b22546d77")]
		// public static extern SAFEARRAY * SafeArrayCreateEx(VARTYPE vt, uint cDims, ref SAFEARRAYBOUND rgsabound, IntPtr pvExtra);
		public static extern SafeSAFEARRAY SafeArrayCreateEx(VARTYPE vt, uint cDims, in SAFEARRAYBOUND rgsabound, in Guid pvExtra);

		/// <summary>
		/// <para>
		/// Creates a one-dimensional array. A safe array created with <c>SafeArrayCreateVector</c> is a fixed size, so the constant
		/// FADF_FIXEDSIZE is always set.
		/// </para>
		/// </summary>
		/// <param name="vt">
		/// <para>
		/// The base type of the array (the VARTYPE of each element of the array). The VARTYPE is restricted to a subset of the variant
		/// types. Neither the VT_ARRAY nor the VT_BYREF flag can be set. VT_EMPTY and VT_NULL are not valid base types for the array. All
		/// other types are legal.
		/// </para>
		/// </param>
		/// <param name="lLbound">
		/// <para>The lower bound for the array. This parameter can be negative.</para>
		/// </param>
		/// <param name="cElements">
		/// <para>The number of elements in the array.</para>
		/// </param>
		/// <returns>
		/// <para>A safe array descriptor, or null if the array could not be created.</para>
		/// </returns>
		// https://docs.microsoft.com/en-us/windows/desktop/api/oleauto/nf-oleauto-safearraycreatevector SAFEARRAY * SafeArrayCreateVector(
		// VARTYPE vt, LONG lLbound, ULONG cElements );
		[DllImport(Lib.OleAut32, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("oleauto.h", MSDNShortId = "b794b8c6-a523-4636-8681-a936dff3fc6f")]
		public static extern SafeSAFEARRAY SafeArrayCreateVector(VARTYPE vt, int lLbound, uint cElements);

		/// <summary>
		/// <para>Creates and returns a one-dimensional safe array of the specified VARTYPE and bounds.</para>
		/// </summary>
		/// <param name="vt">
		/// <para>
		/// The base type of the array (the VARTYPE of each element of the array). The FADF_RECORD flag can be set for VT_RECORD. The
		/// FADF_HAVEIID can be set for VT_DISPATCH or VT_UNKNOWN and FADF_HAVEVARTYPE can be set for all other types.
		/// </para>
		/// </param>
		/// <param name="lLbound">
		/// <para>The lower bound for the array. This parameter can be negative.</para>
		/// </param>
		/// <param name="cElements">
		/// <para>The number of elements in the array.</para>
		/// </param>
		/// <param name="pvExtra">
		/// <para>
		/// The type information of the user-defined type, if you are creating a safe array of user-defined types. If the vt parameter is
		/// VT_RECORD, then pvExtra will be a pointer to an IRecordInfo describing the record. If the vt parameter is VT_DISPATCH or
		/// VT_UNKNOWN, then pvExtra will contain a pointer to a GUID representing the type of interface being passed to the array.
		/// </para>
		/// </param>
		/// <returns>
		/// <para>A safe array descriptor, or null if the array could not be created.</para>
		/// </returns>
		// https://docs.microsoft.com/en-us/windows/desktop/api/oleauto/nf-oleauto-safearraycreatevectorex SAFEARRAY *
		// SafeArrayCreateVectorEx( VARTYPE vt, LONG lLbound, ULONG cElements, PVOID pvExtra );
		[DllImport(Lib.OleAut32, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("oleauto.h", MSDNShortId = "45f2ba42-4189-42eb-9f6c-772198296906")]
		public static extern SafeSAFEARRAY SafeArrayCreateVectorEx(VARTYPE vt, int lLbound, uint cElements, IntPtr pvExtra);

		/// <summary>
		/// <para>Creates and returns a one-dimensional safe array of the specified VARTYPE and bounds.</para>
		/// </summary>
		/// <param name="vt">
		/// <para>
		/// The base type of the array (the VARTYPE of each element of the array). The FADF_RECORD flag can be set for VT_RECORD. The
		/// FADF_HAVEIID can be set for VT_DISPATCH or VT_UNKNOWN and FADF_HAVEVARTYPE can be set for all other types.
		/// </para>
		/// </param>
		/// <param name="lLbound">
		/// <para>The lower bound for the array. This parameter can be negative.</para>
		/// </param>
		/// <param name="cElements">
		/// <para>The number of elements in the array.</para>
		/// </param>
		/// <param name="pvExtra">
		/// <para>
		/// The type information of the user-defined type, if you are creating a safe array of user-defined types. If the vt parameter is
		/// VT_RECORD, then pvExtra will be a pointer to an IRecordInfo describing the record. If the vt parameter is VT_DISPATCH or
		/// VT_UNKNOWN, then pvExtra will contain a pointer to a GUID representing the type of interface being passed to the array.
		/// </para>
		/// </param>
		/// <returns>
		/// <para>A safe array descriptor, or null if the array could not be created.</para>
		/// </returns>
		// https://docs.microsoft.com/en-us/windows/desktop/api/oleauto/nf-oleauto-safearraycreatevectorex SAFEARRAY *
		// SafeArrayCreateVectorEx( VARTYPE vt, LONG lLbound, ULONG cElements, PVOID pvExtra );
		[DllImport(Lib.OleAut32, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("oleauto.h", MSDNShortId = "45f2ba42-4189-42eb-9f6c-772198296906")]
		public static extern SafeSAFEARRAY SafeArrayCreateVectorEx(VARTYPE vt, int lLbound, uint cElements, IRecordInfo pvExtra);

		/// <summary>
		/// <para>Creates and returns a one-dimensional safe array of the specified VARTYPE and bounds.</para>
		/// </summary>
		/// <param name="vt">
		/// <para>
		/// The base type of the array (the VARTYPE of each element of the array). The FADF_RECORD flag can be set for VT_RECORD. The
		/// FADF_HAVEIID can be set for VT_DISPATCH or VT_UNKNOWN and FADF_HAVEVARTYPE can be set for all other types.
		/// </para>
		/// </param>
		/// <param name="lLbound">
		/// <para>The lower bound for the array. This parameter can be negative.</para>
		/// </param>
		/// <param name="cElements">
		/// <para>The number of elements in the array.</para>
		/// </param>
		/// <param name="pvExtra">
		/// <para>
		/// The type information of the user-defined type, if you are creating a safe array of user-defined types. If the vt parameter is
		/// VT_RECORD, then pvExtra will be a pointer to an IRecordInfo describing the record. If the vt parameter is VT_DISPATCH or
		/// VT_UNKNOWN, then pvExtra will contain a pointer to a GUID representing the type of interface being passed to the array.
		/// </para>
		/// </param>
		/// <returns>
		/// <para>A safe array descriptor, or null if the array could not be created.</para>
		/// </returns>
		// https://docs.microsoft.com/en-us/windows/desktop/api/oleauto/nf-oleauto-safearraycreatevectorex SAFEARRAY *
		// SafeArrayCreateVectorEx( VARTYPE vt, LONG lLbound, ULONG cElements, PVOID pvExtra );
		[DllImport(Lib.OleAut32, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("oleauto.h", MSDNShortId = "45f2ba42-4189-42eb-9f6c-772198296906")]
		public static extern SafeSAFEARRAY SafeArrayCreateVectorEx(VARTYPE vt, int lLbound, uint cElements, in Guid pvExtra);

		/// <summary>
		/// <para>
		/// Destroys an existing array descriptor and all of the data in the array. If objects are stored in the array, <c>Release</c> is
		/// called on each object in the array.
		/// </para>
		/// </summary>
		/// <param name="psa">
		/// <para>An array descriptor created by SafeArrayCreate.</para>
		/// </param>
		/// <returns>
		/// <para>This function can return one of these values.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Return code</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>S_OK</term>
		/// <term>Success.</term>
		/// </item>
		/// <item>
		/// <term>E_INVALIDARG</term>
		/// <term>The argument psa is not valid.</term>
		/// </item>
		/// <item>
		/// <term>DISP_E_ARRAYISLOCKED</term>
		/// <term>The array is locked.</term>
		/// </item>
		/// </list>
		/// </returns>
		/// <remarks>
		/// <para>
		/// Safe arrays of variant will have the VariantClear function called on each member and safe arrays of BSTR will have the
		/// SysFreeString function called on each element. IRecordInfo::RecordClear will be called to release object references and other
		/// values of a record without deallocating the record.
		/// </para>
		/// <para>Examples</para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/desktop/api/oleauto/nf-oleauto-safearraydestroy HRESULT SafeArrayDestroy( SAFEARRAY *psa );
		[DllImport(Lib.OleAut32, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("oleauto.h", MSDNShortId = "fc94f7e7-b903-4c78-905c-54df1f8d13fa")]
		public static extern HRESULT SafeArrayDestroy(IntPtr psa);

		/// <summary>
		/// <para>Destroys all the data in the specified safe array.</para>
		/// </summary>
		/// <param name="psa">
		/// <para>A safe array descriptor.</para>
		/// </param>
		/// <returns>
		/// <para>This function can return one of these values.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Return code</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>S_OK</term>
		/// <term>Success.</term>
		/// </item>
		/// <item>
		/// <term>E_INVALIDARG</term>
		/// <term>The argument psa was not valid.</term>
		/// </item>
		/// <item>
		/// <term>DISP_E_ARRAYISLOCKED</term>
		/// <term>The array is locked.</term>
		/// </item>
		/// </list>
		/// </returns>
		/// <remarks>
		/// <para>
		/// This function is typically used when freeing safe arrays that contain elements with data types other than variants. If objects
		/// are stored in the array, Release is called on each object in the array. Safe arrays of variant will have the VariantClear
		/// function called on each member and safe arrays of BSTR will have the SysFreeString function called on each element.
		/// IRecordInfo::RecordClear will be called to release object references and other values of a record without deallocating the record.
		/// </para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/desktop/api/oleauto/nf-oleauto-safearraydestroydata HRESULT SafeArrayDestroyData(
		// SAFEARRAY *psa );
		[DllImport(Lib.OleAut32, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("oleauto.h", MSDNShortId = "aa9c62ba-79b5-4fcf-b3ed-664016486dfc")]
		public static extern HRESULT SafeArrayDestroyData(SafeSAFEARRAY psa);

		/// <summary>
		/// <para>Destroys the descriptor of the specified safe array.</para>
		/// </summary>
		/// <param name="psa">
		/// <para>A safe array descriptor.</para>
		/// </param>
		/// <returns>
		/// <para>This function can return one of these values.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Return code</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>S_OK</term>
		/// <term>Success.</term>
		/// </item>
		/// <item>
		/// <term>E_INVALIDARG</term>
		/// <term>The argument psa was not valid.</term>
		/// </item>
		/// <item>
		/// <term>DISP_E_ARRAYISLOCKED</term>
		/// <term>The array is locked.</term>
		/// </item>
		/// </list>
		/// </returns>
		/// <remarks>
		/// <para>
		/// This function is typically used to destroy the descriptor of a safe array that contains elements with data types other than
		/// variants. Destroying the array descriptor does not destroy the elements in the array. Before destroying the array descriptor,
		/// call SafeArrayDestroyData to free the elements.
		/// </para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/desktop/api/oleauto/nf-oleauto-safearraydestroydescriptor HRESULT
		// SafeArrayDestroyDescriptor( SAFEARRAY *psa );
		[DllImport(Lib.OleAut32, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("oleauto.h", MSDNShortId = "f1e8de45-673b-4f20-a639-18c724c82df1")]
		public static extern HRESULT SafeArrayDestroyDescriptor(IntPtr psa);

		/// <summary>
		/// <para>Gets the number of dimensions in the array.</para>
		/// </summary>
		/// <param name="psa">
		/// <para>An array descriptor created by SafeArrayCreate.</para>
		/// </param>
		/// <returns>
		/// <para>The number of dimensions in the array.</para>
		/// </returns>
		// https://docs.microsoft.com/en-us/windows/desktop/api/oleauto/nf-oleauto-safearraygetdim UINT SafeArrayGetDim( SAFEARRAY *psa );
		[DllImport(Lib.OleAut32, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("oleauto.h", MSDNShortId = "bc52b23b-d323-478c-881f-d2a31a3289c5")]
		public static extern uint SafeArrayGetDim(SafeSAFEARRAY psa);

		/// <summary>
		/// <para>Retrieves a single element of the array.</para>
		/// </summary>
		/// <param name="psa">
		/// <para>An array descriptor created by SafeArrayCreate.</para>
		/// </param>
		/// <param name="rgIndices">
		/// <para>
		/// A vector of indexes for each dimension of the array. The right-most (least significant) dimension is rgIndices[0]. The left-most
		/// dimension is stored at .
		/// </para>
		/// </param>
		/// <param name="pv">
		/// <para>The element of the array.</para>
		/// </param>
		/// <returns>
		/// <para>This function can return one of these values.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Return code</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>S_OK</term>
		/// <term>Success.</term>
		/// </item>
		/// <item>
		/// <term>DISP_E_BADINDEX</term>
		/// <term>The specified index is not valid.</term>
		/// </item>
		/// <item>
		/// <term>E_INVALIDARG</term>
		/// <term>One of the arguments is not valid.</term>
		/// </item>
		/// <item>
		/// <term>E_OUTOFMEMORY</term>
		/// <term>Memory could not be allocated for the element.</term>
		/// </item>
		/// </list>
		/// </returns>
		/// <remarks>
		/// <para>
		/// This function calls SafeArrayLock and SafeArrayUnlock automatically, before and after retrieving the element. The caller must
		/// provide a storage area of the correct size to receive the data. If the data element is a string, object, or variant, the function
		/// copies the element in the correct way.
		/// </para>
		/// <para>Examples</para>
		/// <para>The following example is taken from the COM Fundamentals SPoly sample (Cenumpt.cpp).</para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/desktop/api/oleauto/nf-oleauto-safearraygetelement HRESULT SafeArrayGetElement( SAFEARRAY
		// *psa, LONG *rgIndices, void *pv );
		[DllImport(Lib.OleAut32, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("oleauto.h", MSDNShortId = "47e9ee31-1e3b-4193-8467-6ef0db05966e")]
		public static extern HRESULT SafeArrayGetElement(SafeSAFEARRAY psa, [MarshalAs(UnmanagedType.LPArray)] int[] rgIndices, [Out] IntPtr pv);

		/// <summary>
		/// <para>Gets the size of an element.</para>
		/// </summary>
		/// <param name="psa">
		/// <para>An array descriptor created by SafeArrayCreate.</para>
		/// </param>
		/// <returns>
		/// <para>The size of an element in a safe array, in bytes.</para>
		/// </returns>
		// https://docs.microsoft.com/en-us/windows/desktop/api/oleauto/nf-oleauto-safearraygetelemsize UINT SafeArrayGetElemsize( SAFEARRAY
		// *psa );
		[DllImport(Lib.OleAut32, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("oleauto.h", MSDNShortId = "27bd4a3f-0e9d-45f7-ad7c-0c0b59579dd0")]
		public static extern int SafeArrayGetElemsize(SafeSAFEARRAY psa);

		/// <summary>
		/// <para>Gets the GUID of the interface contained within the specified safe array.</para>
		/// </summary>
		/// <param name="psa">
		/// <para>An array descriptor created by SafeArrayCreate.</para>
		/// </param>
		/// <param name="pguid">
		/// <para>The GUID of the interface.</para>
		/// </param>
		/// <returns>
		/// <para>This function can return one of these values.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Return code</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>S_OK</term>
		/// <term>Success.</term>
		/// </item>
		/// <item>
		/// <term>E_INVALIDARG</term>
		/// <term>The argument psa is null or the array descriptor does not have the FADF_HAVEIID flag set.</term>
		/// </item>
		/// </list>
		/// </returns>
		// https://docs.microsoft.com/en-us/windows/desktop/api/oleauto/nf-oleauto-safearraygetiid HRESULT SafeArrayGetIID( SAFEARRAY *psa,
		// GUID *pguid );
		[DllImport(Lib.OleAut32, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("oleauto.h", MSDNShortId = "9416f7f8-aee0-4e6a-be4f-ca6061adb244")]
		public static extern HRESULT SafeArrayGetIID(SafeSAFEARRAY psa, out Guid pguid);

		/// <summary>
		/// <para>Gets the lower bound for any dimension of the specified safe array.</para>
		/// </summary>
		/// <param name="psa">
		/// <para>An array descriptor created by SafeArrayCreate.</para>
		/// </param>
		/// <param name="nDim">
		/// <para>The array dimension for which to get the lower bound.</para>
		/// </param>
		/// <param name="plLbound">
		/// <para>The lower bound.</para>
		/// </param>
		/// <returns>
		/// <para>This function can return one of these values.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Return code</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>S_OK</term>
		/// <term>Success.</term>
		/// </item>
		/// <item>
		/// <term>E_INVALIDARG</term>
		/// <term>One of the arguments is not valid.</term>
		/// </item>
		/// <item>
		/// <term>DISP_E_BADINDEX</term>
		/// <term>The specified index is out of bounds.</term>
		/// </item>
		/// </list>
		/// </returns>
		// https://docs.microsoft.com/en-us/windows/desktop/api/oleauto/nf-oleauto-safearraygetlbound HRESULT SafeArrayGetLBound( SAFEARRAY
		// *psa, UINT nDim, LONG *plLbound );
		[DllImport(Lib.OleAut32, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("oleauto.h", MSDNShortId = "f3134cc9-759b-4908-ada0-d025a525e795")]
		public static extern HRESULT SafeArrayGetLBound(SafeSAFEARRAY psa, uint nDim, out int plLbound);

		/// <summary>
		/// <para>Retrieves the IRecordInfo interface of the UDT contained in the specified safe array.</para>
		/// </summary>
		/// <param name="psa">
		/// <para>An array descriptor created by SafeArrayCreate.</para>
		/// </param>
		/// <param name="prinfo">
		/// <para>The IRecordInfo interface.</para>
		/// </param>
		/// <returns>
		/// <para>This function can return one of these values.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Return code</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>S_OK</term>
		/// <term>Success.</term>
		/// </item>
		/// <item>
		/// <term>E_INVALIDARG</term>
		/// <term>The argument psa is null or the array descriptor does not have the FADF_RECORD flag set.</term>
		/// </item>
		/// </list>
		/// </returns>
		// https://docs.microsoft.com/en-us/windows/desktop/api/oleauto/nf-oleauto-safearraygetrecordinfo HRESULT SafeArrayGetRecordInfo(
		// SAFEARRAY *psa, IRecordInfo **prinfo );
		[DllImport(Lib.OleAut32, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("oleauto.h", MSDNShortId = "1584c00e-06a5-44f4-8c4b-a2b23737a652")]
		public static extern HRESULT SafeArrayGetRecordInfo(SafeSAFEARRAY psa, out IRecordInfo prinfo);

		/// <summary>
		/// <para>Gets the upper bound for any dimension of the specified safe array.</para>
		/// </summary>
		/// <param name="psa">
		/// <para>An array descriptor created by SafeArrayCreate.</para>
		/// </param>
		/// <param name="nDim">
		/// <para>The array dimension for which to get the upper bound.</para>
		/// </param>
		/// <param name="plUbound">
		/// <para>The upper bound.</para>
		/// </param>
		/// <returns>
		/// <para>This function can return one of these values.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Return code</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>S_OK</term>
		/// <term>Success.</term>
		/// </item>
		/// <item>
		/// <term>DISP_E_BADINDEX</term>
		/// <term>The specified index is out of bounds.</term>
		/// </item>
		/// <item>
		/// <term>DISP_E_OVERFLOW</term>
		/// <term>Overflow occurred while computing the upper bound.</term>
		/// </item>
		/// <item>
		/// <term>E_INVALIDARG</term>
		/// <term>One of the arguments is not valid.</term>
		/// </item>
		/// </list>
		/// </returns>
		// https://docs.microsoft.com/en-us/windows/desktop/api/oleauto/nf-oleauto-safearraygetubound HRESULT SafeArrayGetUBound( SAFEARRAY
		// *psa, UINT nDim, LONG *plUbound );
		[DllImport(Lib.OleAut32, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("oleauto.h", MSDNShortId = "aed339d5-d962-4adc-ac01-6c15a54c51ca")]
		public static extern HRESULT SafeArrayGetUBound(SafeSAFEARRAY psa, uint nDim, out int plUbound);

		/// <summary>
		/// <para>Gets the VARTYPE stored in the specified safe array.</para>
		/// </summary>
		/// <param name="psa">
		/// <para>An array descriptor created by SafeArrayCreate.</para>
		/// </param>
		/// <param name="pvt">
		/// <para>The VARTYPE.</para>
		/// </param>
		/// <returns>
		/// <para>This function can return one of these values.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Return code</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>S_OK</term>
		/// <term>Success.</term>
		/// </item>
		/// <item>
		/// <term>E_INVALIDARG</term>
		/// <term>One of the arguments is not valid.</term>
		/// </item>
		/// </list>
		/// </returns>
		/// <remarks>
		/// <para>
		/// If FADF_HAVEVARTYPE is set, <c>SafeArrayGetVartype</c> returns the VARTYPE stored in the array descriptor. If FADF_RECORD is set,
		/// it returns VT_RECORD; if FADF_DISPATCH is set, it returns VT_DISPATCH; and if FADF_UNKNOWN is set, it returns VT_UNKNOWN.
		/// </para>
		/// <para>
		/// <c>SafeArrayGetVartype</c> can fail to return VT_UNKNOWN for SAFEARRAY types that are based on <c>IUnknown</c>. Callers should
		/// additionally check whether the SAFEARRAY type's <c>fFeatures</c> field has the FADF_UNKNOWN flag set.
		/// </para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/desktop/api/oleauto/nf-oleauto-safearraygetvartype HRESULT SafeArrayGetVartype( SAFEARRAY
		// *psa, VARTYPE *pvt );
		[DllImport(Lib.OleAut32, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("oleauto.h", MSDNShortId = "8ec0e736-bac8-4df4-ba32-433cd8478c55")]
		public static extern HRESULT SafeArrayGetVartype(SafeSAFEARRAY psa, out VARTYPE pvt);

		/// <summary>
		/// <para>Increments the lock count of an array, and places a pointer to the array data in pvData of the array descriptor.</para>
		/// </summary>
		/// <param name="psa">
		/// <para>An array descriptor created by SafeArrayCreate.</para>
		/// </param>
		/// <returns>
		/// <para>This function can return one of these values.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Return code</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>S_OK</term>
		/// <term>Success.</term>
		/// </item>
		/// <item>
		/// <term>E_INVALIDARG</term>
		/// <term>The argument psa is not valid.</term>
		/// </item>
		/// <item>
		/// <term>E_UNEXPECTED</term>
		/// <term>The array could not be locked.</term>
		/// </item>
		/// </list>
		/// </returns>
		/// <remarks>
		/// <para>
		/// The pointer in the array descriptor is valid until the SafeArrayUnlock function is called. Calls to <c>SafeArrayLock</c> can be
		/// nested, in which case an equal number of calls to <c>SafeArrayUnlock</c> are required.
		/// </para>
		/// <para>An array cannot be deleted while it is locked.</para>
		/// <para>Thread Safety</para>
		/// <para>
		/// All public static (Shared in Visual Basic) members of the SAFEARRAY data type are thread safe. Instance members are not
		/// guaranteed to be thread safe.
		/// </para>
		/// <para>
		/// For example, consider an application that uses the SafeArrayLock and SafeArrayUnlock functions. If these functions are called
		/// concurrently from different threads on the same SAFEARRAY data type instance, an inconsistent lock count may be created. This
		/// will eventually cause the <c>SafeArrayUnlock</c> function to return E_UNEXPECTED. You can prevent this by providing your own
		/// synchronization code.
		/// </para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/desktop/api/oleauto/nf-oleauto-safearraylock HRESULT SafeArrayLock( SAFEARRAY *psa );
		[DllImport(Lib.OleAut32, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("oleauto.h", MSDNShortId = "cb29d862-c7c5-4852-b017-c29e88d5f1c4")]
		public static extern HRESULT SafeArrayLock(SafeSAFEARRAY psa);

		/// <summary>Gets a pointer to an array element.</summary>
		/// <param name="psa">An array descriptor created by <c>SafeArrayCreate</c>.</param>
		/// <param name="rgIndices">
		/// An array of index values that identify an element of the array. All indexes for the element must be specified.
		/// </param>
		/// <param name="ppvData">The array element.</param>
		/// <returns>
		/// <para>This function can return one of these values.</para>
		/// <para>
		/// <list type="table">
		/// <listheader>
		/// <term>Return code</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>S_OK</term>
		/// <term>Success.</term>
		/// </item>
		/// <item>
		/// <term>DISP_E_BADINDEX</term>
		/// <term>The specified index is not valid.</term>
		/// </item>
		/// <item>
		/// <term>E_INVALIDARG</term>
		/// <term>One of the arguments is not valid.</term>
		/// </item>
		/// </list>
		/// </para>
		/// </returns>
		// HRESULT SafeArrayPtrOfIndex( _In_ SAFEARRAY *psa, _In_ LONG *rgIndices, _Out_ void **ppvData); https://msdn.microsoft.com/en-us/library/windows/desktop/ms221452(v=vs.85).aspx
		[DllImport(Lib.OleAut32, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("OleAuto.h", MSDNShortId = "ms221452")]
		public static extern HRESULT SafeArrayPtrOfIndex(SafeSAFEARRAY psa, [In] int[] rgIndices, out IntPtr ppvData);

		/// <summary>
		/// <para>Stores the data element at the specified location in the array.</para>
		/// </summary>
		/// <param name="psa">
		/// <para>An array descriptor created by SafeArrayCreate.</para>
		/// </param>
		/// <param name="rgIndices">
		/// <para>
		/// A vector of indexes for each dimension of the array. The right-most (least significant) dimension is rgIndices[0]. The left-most
		/// dimension is stored at .
		/// </para>
		/// </param>
		/// <param name="pv">
		/// <para>
		/// The data to assign to the array. The variant types VT_DISPATCH, VT_UNKNOWN, and VT_BSTR are pointers, and do not require another
		/// level of indirection.
		/// </para>
		/// </param>
		/// <returns>
		/// <para>This function can return one of these values.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Return code</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>S_OK</term>
		/// <term>Success.</term>
		/// </item>
		/// <item>
		/// <term>DISP_E_BADINDEX</term>
		/// <term>The specified index is not valid.</term>
		/// </item>
		/// <item>
		/// <term>E_INVALIDARG</term>
		/// <term>One of the arguments is not valid.</term>
		/// </item>
		/// <item>
		/// <term>E_OUTOFMEMORY</term>
		/// <term>Memory could not be allocated for the element.</term>
		/// </item>
		/// </list>
		/// </returns>
		/// <remarks>
		/// <para>
		/// This function automatically calls SafeArrayLock and SafeArrayUnlock before and after assigning the element. If the data element
		/// is a string, object, or variant, the function copies it correctly when the safe array is destroyed. If the existing element is a
		/// string, object, or variant, it is cleared correctly. If the data element is a VT_DISPATCH or VT_UNKNOWN, <c>AddRef</c> is called
		/// to increment the object's reference count.
		/// </para>
		/// <para><c>Note</c> Multiple locks can be on an array. Elements can be put into an array while the array is locked by other operations.</para>
		/// <para>
		/// For an example that demonstrates calling <c>SafeArrayPutElement</c>, see the COM Fundamentals Lines sample (CLines::Add in Lines.cpp).
		/// </para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/desktop/api/oleauto/nf-oleauto-safearrayputelement HRESULT SafeArrayPutElement( SAFEARRAY
		// *psa, LONG *rgIndices, void *pv );
		[DllImport(Lib.OleAut32, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("oleauto.h", MSDNShortId = "7c837b4f-d319-4d98-934a-b585fe521bf8")]
		public static extern HRESULT SafeArrayPutElement(SafeSAFEARRAY psa, [MarshalAs(UnmanagedType.LPArray)] int[] rgIndices, [In] IntPtr pv);

		/// <summary>
		/// <para>Changes the right-most (least significant) bound of the specified safe array.</para>
		/// </summary>
		/// <param name="psa">
		/// <para>A safe array descriptor.</para>
		/// </param>
		/// <param name="psaboundNew">
		/// <para>
		/// A new safe array bound structure that contains the new array boundary. You can change only the least significant dimension of an array.
		/// </para>
		/// </param>
		/// <returns>
		/// <para>This function can return one of these values.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Return code</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>S_OK</term>
		/// <term>Success.</term>
		/// </item>
		/// <item>
		/// <term>E_INVALIDARG</term>
		/// <term>The argument psa is not valid.</term>
		/// </item>
		/// <item>
		/// <term>DISP_E_ARRAYISLOCKED</term>
		/// <term>The array is locked.</term>
		/// </item>
		/// </list>
		/// </returns>
		/// <remarks>
		/// <para>
		/// If you reduce the bound of an array, <c>SafeArrayRedim</c> deallocates the array elements outside the new array boundary. If the
		/// bound of an array is increased, <c>SafeArrayRedim</c> allocates and initializes the new array elements. The data is preserved for
		/// elements that exist in both the old and new array.
		/// </para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/desktop/api/oleauto/nf-oleauto-safearrayredim HRESULT SafeArrayRedim( SAFEARRAY *psa,
		// SAFEARRAYBOUND *psaboundNew );
		[DllImport(Lib.OleAut32, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("oleauto.h", MSDNShortId = "1c7fa627-e5e4-4bb9-8237-2f7358ebc4b8")]
		public static extern HRESULT SafeArrayRedim(SafeSAFEARRAY psa, in SAFEARRAYBOUND psaboundNew);

		/// <summary>
		/// <para>The safe array data for which the pinning reference count should decrease.</para>
		/// </summary>
		/// <param name="pData">
		/// <para>The safe array data for which the pinning reference count should decrease.</para>
		/// </param>
		/// <returns>
		/// <para>This function does not return a value.</para>
		/// </returns>
		/// <remarks>
		/// <para>
		/// A call to the <c>SafeArrayReleaseData</c> function should match every previous call to the SafeArrayAddRef function that returned
		/// a non-null value in the ppDataToRelease parameter.
		/// </para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/desktop/api/oleauto/nf-oleauto-safearrayreleasedata void SafeArrayReleaseData( PVOID
		// pData );
		[DllImport(Lib.OleAut32, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("oleauto.h", MSDNShortId = "AF3C36A3-2B3A-4159-8183-DB082FBFD215")]
		public static extern void SafeArrayReleaseData(IntPtr pData);

		/// <summary>
		/// <para>The safe array for which the pinning reference count of the descriptor should decrease.</para>
		/// </summary>
		/// <param name="psa">
		/// <para>The safe array for which the pinning reference count of the descriptor should decrease.</para>
		/// </param>
		/// <returns>
		/// <para>This function does not return a value.</para>
		/// </returns>
		/// <remarks>
		/// <para>A call to the <c>SafeArrayReleaseDescriptor</c> function should match every previous call to the SafeArrayAddRef function.</para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/desktop/api/oleauto/nf-oleauto-safearrayreleasedescriptor void
		// SafeArrayReleaseDescriptor( SAFEARRAY *psa );
		[DllImport(Lib.OleAut32, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("oleauto.h", MSDNShortId = "D6678B17-B537-46CF-AC64-4D0C0DC4CDF3")]
		public static extern void SafeArrayReleaseDescriptor(SafeSAFEARRAY psa);

		/// <summary>
		/// <para>Sets the GUID of the interface for the specified safe array.</para>
		/// </summary>
		/// <param name="psa">
		/// <para>The safe array descriptor.</para>
		/// </param>
		/// <param name="guid">
		/// <para>The IID.</para>
		/// </param>
		/// <returns>
		/// <para>This function can return one of these values.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Return code</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>S_OK</term>
		/// <term>Success.</term>
		/// </item>
		/// <item>
		/// <term>E_INVALIDARG</term>
		/// <term>The argument psa is null or the array descriptor does not have the FADF_HAVEIID flag set.</term>
		/// </item>
		/// </list>
		/// </returns>
		// https://docs.microsoft.com/en-us/windows/desktop/api/oleauto/nf-oleauto-safearraysetiid HRESULT SafeArraySetIID( SAFEARRAY *psa,
		// REFGUID guid );
		[DllImport(Lib.OleAut32, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("oleauto.h", MSDNShortId = "851b8a44-9da4-418c-88bc-80c9fc55d25c")]
		public static extern HRESULT SafeArraySetIID(SafeSAFEARRAY psa, in Guid guid);

		/// <summary>
		/// <para>Sets the record info in the specified safe array.</para>
		/// </summary>
		/// <param name="psa">
		/// <para>The array descriptor.</para>
		/// </param>
		/// <param name="prinfo">
		/// <para>The record info.</para>
		/// </param>
		/// <returns>
		/// <para>This function can return one of these values.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Return code</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>S_OK</term>
		/// <term>Success.</term>
		/// </item>
		/// <item>
		/// <term>E_INVALIDARG</term>
		/// <term>The argument psa is null or the array descriptor does not have the FADF_RECORD flag set.</term>
		/// </item>
		/// </list>
		/// </returns>
		// https://docs.microsoft.com/en-us/windows/desktop/api/oleauto/nf-oleauto-safearraysetrecordinfo HRESULT SafeArraySetRecordInfo(
		// SAFEARRAY *psa, IRecordInfo *prinfo );
		[DllImport(Lib.OleAut32, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("oleauto.h", MSDNShortId = "85317e8e-7625-4799-9c34-73245f164f85")]
		public static extern HRESULT SafeArraySetRecordInfo(SafeSAFEARRAY psa, IRecordInfo prinfo);

		/// <summary>
		/// <para>Decrements the lock count of an array, and invalidates the pointer retrieved by SafeArrayAccessData.</para>
		/// </summary>
		/// <param name="psa">
		/// <para>An array descriptor created by SafeArrayCreate.</para>
		/// </param>
		/// <returns>
		/// <para>This function can return one of these values.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Return code</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>S_OK</term>
		/// <term>Success.</term>
		/// </item>
		/// <item>
		/// <term>E_INVALIDARG</term>
		/// <term>The argument psa is not valid.</term>
		/// </item>
		/// <item>
		/// <term>E_UNEXPECTED</term>
		/// <term>The array could not be unlocked.</term>
		/// </item>
		/// </list>
		/// </returns>
		// https://docs.microsoft.com/en-us/windows/desktop/api/oleauto/nf-oleauto-safearrayunaccessdata HRESULT SafeArrayUnaccessData(
		// SAFEARRAY *psa );
		[DllImport(Lib.OleAut32, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("oleauto.h", MSDNShortId = "61b482cb-f0a3-4efb-9a68-f373f241e89a")]
		public static extern HRESULT SafeArrayUnaccessData(SafeSAFEARRAY psa);

		/// <summary>
		/// <para>Decrements the lock count of an array so it can be freed or resized.</para>
		/// </summary>
		/// <param name="psa">
		/// <para>An array descriptor created by SafeArrayCreate.</para>
		/// </param>
		/// <returns>
		/// <para>This function can return one of these values.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Return code</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>S_OK</term>
		/// <term>Success.</term>
		/// </item>
		/// <item>
		/// <term>E_INVALIDARG</term>
		/// <term>The argument psa is not valid.</term>
		/// </item>
		/// <item>
		/// <term>E_UNEXPECTED</term>
		/// <term>The array could not be unlocked.</term>
		/// </item>
		/// </list>
		/// </returns>
		/// <remarks>
		/// <para>This function is called after access to the data in an array is finished.</para>
		/// <para>Thread Safety</para>
		/// <para>
		/// All public static members of the SAFEARRAY data type are thread safe. Instance members are not guaranteed to be thread safe.
		/// </para>
		/// <para>
		/// For example, consider an application that uses the SafeArrayLock and SafeArrayUnlock functions. If these functions are called
		/// concurrently from different threads on the same SAFEARRAY data type instance, an inconsistent lock count may be created. This
		/// will eventually cause the SafeArrayUnlock function to return E_UNEXPECTED. You can prevent this by providing your own
		/// synchronization code.
		/// </para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/desktop/api/oleauto/nf-oleauto-safearrayunlock HRESULT SafeArrayUnlock( SAFEARRAY *psa );
		[DllImport(Lib.OleAut32, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("oleauto.h", MSDNShortId = "654995ab-1959-44dc-9e26-11c34e489c14")]
		public static extern HRESULT SafeArrayUnlock(SafeSAFEARRAY psa);

		/// <summary>Represents a safe array.</summary>
		/// <seealso cref="System.IDisposable"/>
		[StructLayout(LayoutKind.Sequential, Pack = 4)]
		[PInvokeData("OaIdl.h", MSDNShortId = "ms221482")]
		public struct SAFEARRAY
		{
			/// <summary>The number of dimensions.</summary>
			public ushort cDims;

			/// <summary>Flags.</summary>
			public ADVFEATUREFLAGS fFeatures;

			/// <summary>The size of an array element.</summary>
			public uint cbElements;

			/// <summary>The number of times the array has been locked without a corresponding unlock.</summary>
			public uint cLocks;

			/// <summary>The data.</summary>
			public IntPtr pvData;

			/// <summary>One bound for each dimension.</summary>
			public IntPtr rgsabound;

			/// <summary>Gets the bounds pointed to by <see cref="rgsabound"/>.</summary>
			public SAFEARRAYBOUND[] Bounds => rgsabound.ToArray<SAFEARRAYBOUND>(cDims);
		}

		/// <summary>Represents the bounds of one dimension of the array.</summary>
		[StructLayout(LayoutKind.Sequential, Pack = 4)]
		[PInvokeData("OaIdl.h", MSDNShortId = "ms221167")]
		public struct SAFEARRAYBOUND
		{
			/// <summary>The number of elements in the dimension.</summary>
			public uint cElements;

			/// <summary>The lower bound of the dimension.</summary>
			public int lLbound;

			/// <summary>Initializes a new instance of the <see cref="SAFEARRAYBOUND"/> struct.</summary>
			/// <param name="upperBound">The number of elements in the dimension.</param>
			/// <param name="lowerBound">The lower bound of the dimension.</param>
			public SAFEARRAYBOUND(uint upperBound, int lowerBound = 0)
			{
				cElements = upperBound;
				lLbound = lowerBound;
			}
		}

		/// <summary>Provides a <see cref="SafeHandle"/> to a safe array that releases a created SAFEARRAY instance at disposal using SafeArrayDestroy.</summary>
		public class SafeSAFEARRAY : SafeHANDLE
		{
			/// <summary>Initializes a new instance of the <see cref="SafeSAFEARRAY"/> class and assigns an existing handle.</summary>
			/// <param name="preexistingHandle">An <see cref="IntPtr"/> object that represents the pre-existing handle to use.</param>
			/// <param name="ownsHandle"><see langword="true"/> to reliably release the handle during the finalization phase; otherwise, <see langword="false"/> (not recommended).</param>
			public SafeSAFEARRAY(IntPtr preexistingHandle, bool ownsHandle = true) : base(preexistingHandle, ownsHandle) { }

			/// <summary>Initializes a new instance of the <see cref="SafeSAFEARRAY"/> class.</summary>
			protected SafeSAFEARRAY() : base() { }

			/// <summary>Performs an implicit conversion from <see cref="SafeSAFEARRAY"/> to <see cref="SAFEARRAY"/>.</summary>
			/// <param name="h">The safe handle instance.</param>
			/// <returns>The result of the conversion.</returns>
			public static implicit operator SAFEARRAY(SafeSAFEARRAY h) => h.IsInvalid ? new SAFEARRAY() : h.handle.ToStructure<SAFEARRAY>();

			/// <inheritdoc/>
			protected override bool InternalReleaseHandle() => SafeArrayDestroy(handle).Succeeded;
		}

		/// <summary>Provides a safe handle for items created with <see cref="SafeArrayAllocDescriptor"/>.</summary>
		/// <seealso cref="Vanara.PInvoke.OleAut32.SafeSAFEARRAY"/>
		public class SafeDescriptorSAFEARRAY : SafeSAFEARRAY
		{
			/// <summary>Initializes a new instance of the <see cref="SafeDescriptorSAFEARRAY"/> class and assigns an existing handle.</summary>
			/// <param name="preexistingHandle">An <see cref="IntPtr"/> object that represents the pre-existing handle to use.</param>
			/// <param name="ownsHandle"><see langword="true"/> to reliably release the handle during the finalization phase; otherwise, <see langword="false"/> (not recommended).</param>
			public SafeDescriptorSAFEARRAY(IntPtr preexistingHandle, bool ownsHandle = true) : base(preexistingHandle, ownsHandle) { }

			/// <summary>Initializes a new instance of the <see cref="SafeDescriptorSAFEARRAY"/> class.</summary>
			private SafeDescriptorSAFEARRAY() : base() { }

			/// <inheritdoc/>
			protected override bool InternalReleaseHandle() => SafeArrayDestroyDescriptor(handle).Succeeded;
		}

		/// <summary>Construct for handling the paired calling of <see cref="SafeArrayAccessData"/> and <see cref="SafeArrayUnaccessData"/>.</summary>
		/// <example>
		/// <code>
		/// using (var data = new SafeArrayScopedAccessData(safeArray))
		/// {
		/// // The Data property provides access to the array's data while in scope.
		/// FILETIME ft = (FILETIME)Marshal.PtrToStructure(data.Data, typeof(FILETIME));
		/// }
		/// </code>
		/// </example>
		/// <seealso cref="System.IDisposable"/>
		[PInvokeData("OleAuto.h")]
		public class SafeArrayScopedAccessData : IDisposable
		{
			private readonly SafeSAFEARRAY psa;
			private IntPtr ppvData;

			/// <summary>
			/// Initializes a new instance of the <see cref="SafeArrayScopedAccessData"/> class using the array descriptor that holds the data.
			/// </summary>
			/// <param name="psa">An array descriptor created by SafeArrayCreate.</param>
			public SafeArrayScopedAccessData(SafeSAFEARRAY psa)
			{
				var hr = SafeArrayAccessData(psa, out ppvData);
				hr.ThrowIfFailed();
				this.psa = psa;
			}

			/// <summary>Gets the pointer exposed by the call to <see cref="SafeArrayAccessData"/>.</summary>
			/// <value>A pointer to the raw data within the array descriptor.</value>
			public IntPtr Data => ppvData;

			/// <summary>Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.</summary>
			public void Dispose()
			{
				SafeArrayUnaccessData(psa);
				ppvData = IntPtr.Zero;
			}
		}
	}
}