using System;
using System.Runtime.InteropServices;
using Vanara.InteropServices;

namespace Vanara.PInvoke
{
	/// <summary>Methods and data types found in Crypt32.dll.</summary>
	public static partial class Crypt32
	{
		/// <summary>Decoding options.</summary>
		[PInvokeData("wincrypt.h", MSDNShortId = "7d5ed4f4-9d76-4a16-9059-27b0edd83459")]
		[Flags]
		public enum CryptDecodeFlags
		{
			/// <summary>
			/// This flag can be set to indicate that "no copy" optimization is enabled. This optimization, where applicable, updates the
			/// pvStructInfo parameter to point to content residing within pbEncoded instead of making a copy of the content and appending
			/// it to pvStructInfo. For applicable cases, less memory needs to be allocated by the calling application and execution is
			/// faster because a copy is not being made. Note that the trade-off when performing a "no copy" decoding is that pbEncoded
			/// cannot be freed until pvStructInfo is freed.
			/// </summary>
			CRYPT_DECODE_NOCOPY_FLAG = 0x1,

			/// <summary>
			/// By default, the contents of the buffer pointed to by pbEncoded included the signed content and the signature. If this flag
			/// is set, the buffer includes only the "to be signed" content. This flag is applicable to X509_CERT_TO_BE_SIGNED,
			/// X509_CERT_CRL_TO_BE_SIGNED, X509_CRT_REQUEST_TO_BE_SIGNED, and X509_KEYGEN_REQUEST_TO_BE_SIGNED objects.
			/// </summary>
			CRYPT_DECODE_TO_BE_SIGNED_FLAG = 0x2,

			/// <summary>
			/// When this flag is set, the OID stings are allocated in Crypt32.dll and shared instead of being copied into the returned data
			/// structure. This flag can be set if Crypt32.dll is not unloaded before the caller is unloaded.
			/// </summary>
			CRYPT_DECODE_SHARE_OID_STRING_FLAG = 0x4,

			/// <summary>By default, the signature bytes are reversed. If this flag is set, this byte reversal is inhibited.</summary>
			CRYPT_DECODE_NO_SIGNATURE_BYTE_REVERSAL_FLAG = 0x8,

			/// <summary>
			/// The called decoding function allocates memory for the decoded structure. A pointer to the allocated structure is returned in pvStructInfo.
			/// <para>
			/// If pDecodePara or the pfnAlloc member of pDecodePara is NULL, then LocalAlloc is called for the allocation and LocalFree
			/// must be called to free the memory.
			/// </para>
			/// <para>
			/// If pDecodePara and the pfnAlloc member of pDecodePara are not NULL, then the function pointed to by pfnAlloc is called for
			/// the allocation and the function pointed to by the pfnFree member of pDecodePara must be called to free the memory.
			/// </para>
			/// </summary>
			CRYPT_DECODE_ALLOC_FLAG = 0x8000,

			/// <summary>
			/// This flag is applicable when decoding X509_UNICODE_NAME, X509_UNICODE_NAME_VALUE, or X509_UNICODE_ANY_STRING. By default,
			/// CERT_RDN_T61_STRING encoded values are initially decoded as UTF8. If the UTF8 decoding fails, then the value is decoded as
			/// eight-bit characters. If this flag is set, it skips the initial attempt to decode the value as UTF8 and decodes the value as
			/// eight-bit characters.
			/// </summary>
			CRYPT_UNICODE_NAME_DECODE_DISABLE_IE4_UTF8_FLAG = 0x01000000,

			/// <summary>
			/// This flag is applicable for enabling Punycode decoding of Unicode string values. For more information, see Remarks.
			/// <para>Windows Server 2008, Windows Vista, Windows Server 2003 and Windows XP: This flag is not supported.</para>
			/// </summary>
			CRYPT_DECODE_ENABLE_PUNYCODE_FLAG = 0x02000000,

			/// <summary/>
			CRYPT_DECODE_ENABLE_UTF8PERCENT_FLAG = 0x04000000,

			/// <summary/>
			CRYPT_DECODE_ENABLE_IA5CONVERSION_FLAG = CRYPT_DECODE_ENABLE_PUNYCODE_FLAG | CRYPT_DECODE_ENABLE_UTF8PERCENT_FLAG,
		}

		/// <summary>Specifies options for the encoding.</summary>
		[PInvokeData("wincrypt.h", MSDNShortId = "45134db8-059b-43d3-90c2-9b6cc970fca0")]
		[Flags]
		public enum CryptEncodeFlags : uint
		{
			/// <summary/>
			CRYPT_ENCODE_NO_SIGNATURE_BYTE_REVERSAL_FLAG = 0x8,

			/// <summary>
			/// The called encoding function allocates memory for the encoded bytes. A pointer to the allocated bytes is returned in pvEncoded.
			/// </summary>
			CRYPT_ENCODE_ALLOC_FLAG = 0x8000,

			/// <summary> This flag is applicable when encoding X509_UNICODE_NAME. If this flag is set and all the Unicode characters are &lt;=
			/// 0xFF, the CERT_RDN_T61_STRING is selected instead of the CERT_RDN_UNICODE_STRING. </summary>
			CRYPT_UNICODE_NAME_ENCODE_ENABLE_T61_UNICODE_FLAG = 0x80000000,

			/// <summary>
			/// This flag is applicable when encoding an X509_UNICODE_NAME. When set, CERT_RDN_UTF8_STRING is selected instead of CERT_RDN_UNICODE_STRING.
			/// </summary>
			CRYPT_UNICODE_NAME_ENCODE_ENABLE_UTF8_UNICODE_FLAG = 0x20000000,

			/// <summary>
			/// This flag is applicable when encoding an X509_UNICODE_NAME. When set, CERT_RDN_UTF8_STRING is selected instead of
			/// CERT_RDN_PRINTABLE_STRING for directory string types. Also, this flag enables CRYPT_UNICODE_NAME_ENCODE_ENABLE_UTF8_UNICODE_FLAG.
			/// </summary>
			CRYPT_UNICODE_NAME_ENCODE_FORCE_UTF8_UNICODE_FLAG = 0x10000000,

			/// <summary>
			/// This flag is applicable when encoding X509_UNICODE_NAME, X509_UNICODE_NAME_VALUE, or X509_UNICODE_ANY_STRING. If this flag
			/// is set, the characters are not checked to determine whether they are valid for the specified value type.
			/// </summary>
			CRYPT_UNICODE_NAME_ENCODE_DISABLE_CHECK_TYPE_FLAG = 0x40000000,

			/// <summary/>
			CRYPT_SORTED_CTL_ENCODE_HASHED_SUBJECT_IDENTIFIER_FLAG = 0x10000,

			/// <summary>
			/// This flag is applicable for enabling Punycode encoding of Unicode string values. For more information, see Remarks.
			/// <para>Windows Server 2008, Windows Vista, Windows Server 2003 and Windows XP: This flag is not supported.</para>
			/// </summary>
			CRYPT_ENCODE_ENABLE_PUNYCODE_FLAG = 0x20000,

			/// <summary/>
			CRYPT_ENCODE_ENABLE_UTF8PERCENT_FLAG = 0x40000,

			/// <summary/>
			CRYPT_ENCODE_ENABLE_IA5CONVERSION_FLAG = CRYPT_ENCODE_ENABLE_PUNYCODE_FLAG | CRYPT_ENCODE_ENABLE_UTF8PERCENT_FLAG,
		}

		/// <summary>
		/// The <c>CryptDecodeObject</c> function decodes a structure of the type indicated by the lpszStructType parameter. The use of
		/// CryptDecodeObjectEx is recommended as an API that performs the same function with significant performance improvements.
		/// </summary>
		/// <param name="dwCertEncodingType">
		/// <para>
		/// Type of encoding used. It is always acceptable to specify both the certificate and message encoding types by combining them with
		/// a bitwise- <c>OR</c> operation as shown in the following example:
		/// </para>
		/// <para>X509_ASN_ENCODING | PKCS_7_ASN_ENCODING</para>
		/// <para>Currently defined encoding types are:</para>
		/// <list type="bullet">
		/// <item>
		/// <term>X509_ASN_ENCODING</term>
		/// </item>
		/// <item>
		/// <term>PKCS_7_ASN_ENCODING</term>
		/// </item>
		/// </list>
		/// <para>
		/// <c>Note</c> Either a certificate or message encoding type is required. X509_ASN_ENCODING is the default. If that type is
		/// indicated, it is used. Otherwise, if the PKCS7_ASN_ENCODING type is indicated, it is used.
		/// </para>
		/// </param>
		/// <param name="lpszStructType">
		/// <para>
		/// A pointer to an OID defining the structure type. If the high-order word of the lpszStructType parameter is zero, the low-order
		/// word specifies the integer identifier for the type of the specified structure. Otherwise, this parameter is a long pointer to a
		/// null-terminated string.
		/// </para>
		/// <para>
		/// For more information about object identifier strings, their predefined constants and corresponding structures, see Constants for
		/// CryptEncodeObject and CryptDecodeObject.
		/// </para>
		/// </param>
		/// <param name="pbEncoded">A pointer to the encoded structure to be decoded.</param>
		/// <param name="cbEncoded">Number of bytes pointed to by pbEncoded.</param>
		/// <param name="dwFlags">
		/// <para>The following flags are defined. They can be combined with a bitwise- <c>OR</c> operation.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>CRYPT_DECODE_NOCOPY_FLAG</term>
		/// <term>
		/// This flag can be set to indicate that "no copy" optimization is enabled. This optimization, where applicable, updates the
		/// pvStructInfo parameter to point to content residing within pbEncoded instead of making a copy of the content and appending it to
		/// pvStructInfo. For applicable cases, less memory needs to be allocated by the calling application and execution is faster because
		/// a copy is not being made. Note that the trade-off when performing a "no copy" decoding is that pbEncoded cannot be freed until
		/// pvStructInfo is freed.
		/// </term>
		/// </item>
		/// <item>
		/// <term>CRYPT_UNICODE_NAME_DECODE_DISABLE_IE4_UTF8_FLAG</term>
		/// <term>
		/// This flag is applicable when decoding X509_UNICODE_NAME, X509_UNICODE_NAME_VALUE, or X509_UNICODE_ANY_STRING. By default,
		/// CERT_RDN_T61_STRING encoded values are initially decoded as UTF8. If the UTF8 decoding fails, then the value is decoded as
		/// eight-bit characters. If this flag is set, it skips the initial attempt to decode the value as UTF8 and decodes the value as
		/// eight-bit characters.
		/// </term>
		/// </item>
		/// <item>
		/// <term>CRYPT_DECODE_TO_BE_SIGNED_FLAG</term>
		/// <term>
		/// By default, the contents of the buffer pointed to by pbEncoded included the signed content and the signature. If this flag is
		/// set, the buffer includes only the "to be signed" content. This flag is applicable to X509_CERT_TO_BE_SIGNED,
		/// X509_CERT_CRL_TO_BE_SIGNED, X509_CRT_REQUEST_TO_BE_SIGNED, and X509_KEYGEN_REQUEST_TO_BE_SIGNED objects.
		/// </term>
		/// </item>
		/// <item>
		/// <term>CRYPT_DECODE_SHARE_OID_STRING_FLAG</term>
		/// <term>
		/// When this flag is set, the OID stings are allocated in Crypt32.dll and shared instead of being copied into the returned data
		/// structure. This flag can be set if Crypt32.dll is not unloaded before the caller is unloaded.
		/// </term>
		/// </item>
		/// <item>
		/// <term>CRYPT_DECODE_NO_SIGNATURE_BYTE_REVERSAL_FLAG</term>
		/// <term>By default, the signature bytes are reversed. If this flag is set, this byte reversal is inhibited.</term>
		/// </item>
		/// </list>
		/// </param>
		/// <param name="pvStructInfo">
		/// <para>
		/// A pointer to a buffer to receive the decoded structure. When the buffer that is specified is not large enough to receive the
		/// decoded structure, the function sets the ERROR_MORE_DATA code and stores the required buffer size, in bytes, in the variable
		/// pointed to by pcbStructInfo.
		/// </para>
		/// <para>
		/// This parameter can be <c>NULL</c> to retrieve the size of this information for memory allocation purposes. For more information,
		/// see Retrieving Data of Unknown Length.
		/// </para>
		/// </param>
		/// <param name="pcbStructInfo">
		/// <para>
		/// A pointer to a <c>DWORD</c> value specifying the size, in bytes, of the buffer pointed to by the pvStructInfo parameter. When
		/// the function returns, this <c>DWORD</c> value contains the size of the decoded data copied to pvStructInfo. The size contained
		/// in the variable pointed to by pcbStructInfo can indicate a size larger than the decoded structure, as the decoded structure can
		/// include pointers to other structures. This size is the sum of the size needed by the decoded structure and other structures
		/// pointed to.
		/// </para>
		/// <para>
		/// <c>Note</c> When processing the data returned in the buffer, applications must use the actual size of the data returned. The
		/// actual size can be slightly smaller than the size of the buffer specified on input. (On input, buffer sizes are usually
		/// specified large enough to ensure that the largest possible output data fits in the buffer.) On output, the variable pointed to
		/// by this parameter is updated to reflect the actual size of the data copied to the buffer.
		/// </para>
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, the return value is nonzero ( <c>TRUE</c>).</para>
		/// <para>
		/// If the function fails, the return value is zero ( <c>FALSE</c>). For extended error information, call GetLastError. Some
		/// possible error codes are listed in the following table.
		/// </para>
		/// <list type="table">
		/// <listheader>
		/// <term>Return code</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>CRYPT_E_BAD_ENCODE</term>
		/// <term>An error was encountered while decoding.</term>
		/// </item>
		/// <item>
		/// <term>ERROR_FILE_NOT_FOUND</term>
		/// <term>A decoding function could not be found for the specified dwCertEncodingType and lpszStructType</term>
		/// </item>
		/// <item>
		/// <term>ERROR_MORE_DATA</term>
		/// <term>
		/// If the buffer specified by the pvStructInfo parameter is not large enough to hold the returned data, the function sets the
		/// ERROR_MORE_DATA code and stores the required buffer size, in bytes, in the variable pointed to by pcbStructInfo.
		/// </term>
		/// </item>
		/// </list>
		/// <para>
		/// If the function fails, GetLastError may return an Abstract Syntax Notation One (ASN.1) encoding/decoding error. For information
		/// about these errors, see ASN.1 Encoding/Decoding Return Values.
		/// </para>
		/// </returns>
		/// <remarks>
		/// <para>
		/// When encoding a cryptographic object using the preferred CryptEncodeObjectEx function, the terminating <c>NULL</c> character is
		/// included. When decoding, using the preferred CryptDecodeObjectEx function, the terminating <c>NULL</c> character is not retained.
		/// </para>
		/// <para>Examples</para>
		/// <para>For an example that uses this function, see Example C Program: ASN.1 Encoding and Decoding.</para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptdecodeobject BOOL CryptDecodeObject( DWORD
		// dwCertEncodingType, LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD
		// *pcbStructInfo );
		[DllImport(Lib.Crypt32, SetLastError = true, ExactSpelling = true)]
		[PInvokeData("wincrypt.h", MSDNShortId = "7d5ed4f4-9d76-4a16-9059-27b0edd83459")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool CryptDecodeObject(CertEncodingType dwCertEncodingType, [In] SafeOID lpszStructType, [In] IntPtr pbEncoded, uint cbEncoded,
			CryptDecodeFlags dwFlags, [Out] IntPtr pvStructInfo, ref uint pcbStructInfo);

		/// <summary>
		/// The <c>CryptDecodeObjectEx</c> function decodes a structure of the type indicated by the lpszStructType parameter.
		/// <c>CryptDecodeObjectEx</c> offers a significant performance improvement over CryptDecodeObject by supporting memory allocation
		/// with the CRYPT_DECODE_ALLOC_FLAG value.
		/// </summary>
		/// <param name="dwCertEncodingType">
		/// <para>
		/// The type of encoding used. It is always acceptable to specify both the certificate and message encoding types by combining them
		/// with a bitwise- <c>OR</c> operation as shown in the following example:
		/// </para>
		/// <para>X509_ASN_ENCODING | PKCS_7_ASN_ENCODING</para>
		/// <para>Currently defined encoding types are:</para>
		/// <list type="bullet">
		/// <item>
		/// <term>X509_ASN_ENCODING</term>
		/// </item>
		/// <item>
		/// <term>PKCS_7_ASN_ENCODING</term>
		/// </item>
		/// </list>
		/// <para>
		/// <c>Note</c> Either a certificate or message encoding type is required. X509_ASN_ENCODING is the default. If that type is
		/// indicated, it is used. Otherwise, if the PKCS7_ASN_ENCODING type is indicated, it is used.
		/// </para>
		/// </param>
		/// <param name="lpszStructType">
		/// <para>
		/// A pointer to an object identifier (OID) that defines the structure type. If the high-order word of the lpszStructType parameter
		/// is zero, the low-order word specifies the integer identifier for the type of the specified structure. Otherwise, this parameter
		/// is a long pointer to a null-terminated string.
		/// </para>
		/// <para>
		/// For more information about object identifier strings, their predefined constants, and corresponding structures, see Constants
		/// for CryptEncodeObject and CryptDecodeObject.
		/// </para>
		/// </param>
		/// <param name="pbEncoded">A pointer to the data to be decoded. The structure must be of the type specified by lpszStructType.</param>
		/// <param name="cbEncoded">The number of bytes pointed to by pbEncoded. This is the number of bytes to be decoded.</param>
		/// <param name="dwFlags">
		/// <para>This parameter can be one or more of the following flags. The flags can be combined by using a bitwise- <c>OR</c> operation.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>CRYPT_DECODE_ALLOC_FLAG</term>
		/// <term>
		/// The called decoding function allocates memory for the decoded structure. A pointer to the allocated structure is returned in
		/// pvStructInfo. If pDecodePara or the pfnAlloc member of pDecodePara is NULL, then LocalAlloc is called for the allocation and
		/// LocalFree must be called to free the memory. If pDecodePara and the pfnAlloc member of pDecodePara are not NULL, then the
		/// function pointed to by pfnAlloc is called for the allocation and the function pointed to by the pfnFree member of pDecodePara
		/// must be called to free the memory.
		/// </term>
		/// </item>
		/// <item>
		/// <term>CRYPT_DECODE_ENABLE_PUNYCODE_FLAG 33554432 (0x2000000)</term>
		/// <term>
		/// This flag is applicable for enabling Punycode decoding of Unicode string values. For more information, see Remarks. Windows
		/// Server 2008, Windows Vista, Windows Server 2003 and Windows XP: This flag is not supported.
		/// </term>
		/// </item>
		/// <item>
		/// <term>CRYPT_DECODE_NOCOPY_FLAG</term>
		/// <term>
		/// This flag can be set to enable a "no copy" optimization. This optimization updates the pvStructInfo members to point to content
		/// that resides within pbEncoded instead of making a copy of the content and appending it to pvStructInfo. The calling application
		/// needs to allocate less memory and execution is faster because a copy is not made. Note that when performing "no copy" decoding,
		/// pbEncoded cannot be freed until pvStructInfo is freed.
		/// </term>
		/// </item>
		/// <item>
		/// <term>CRYPT_UNICODE_NAME_DECODE_DISABLE_IE4_UTF8_FLAG</term>
		/// <term>
		/// This flag is applicable when decoding X509_UNICODE_NAME, X509_UNICODE_NAME_VALUE, or X509_UNICODE_ANY_STRING. By default,
		/// CERT_RDN_T61_STRING encoded values are initially decoded as UTF8. If the UTF8 decoding fails, then the value is decoded as
		/// eight-bit characters. If this flag is set, it skips the initial attempt to decode the value as UTF8 and decodes the value as
		/// eight-bit characters.
		/// </term>
		/// </item>
		/// <item>
		/// <term>CRYPT_DECODE_TO_BE_SIGNED_FLAG</term>
		/// <term>
		/// By default, the contents of the buffer pointed to by pbEncoded included the signed content and the signature. If this flag is
		/// set, the buffer includes only the "to be signed" content. This flag is applicable to X509_CERT_TO_BE_SIGNED,
		/// X509_CERT_CRL_TO_BE_SIGNED, X509_CRT_REQUEST_TO_BE_SIGNED, and X509_KEYGEN_REQUEST_TO_BE_SIGNED objects.
		/// </term>
		/// </item>
		/// <item>
		/// <term>CRYPT_DECODE_SHARE_OID_STRING_FLAG</term>
		/// <term>
		/// When this flag is set, the OID strings are allocated in Crypt32.dll and shared instead of being copied into the returned data
		/// structure. This flag can be set if Crypt32.dll is not unloaded before the caller is unloaded.
		/// </term>
		/// </item>
		/// <item>
		/// <term>CRYPT_DECODE_NO_SIGNATURE_BYTE_REVERSAL_FLAG</term>
		/// <term>By default, the signature bytes are reversed. If this flag is set, this byte reversal is inhibited.</term>
		/// </item>
		/// </list>
		/// </param>
		/// <param name="pDecodePara">
		/// A pointer to a CRYPT_DECODE_PARA structure that contains decoding paragraph information. If pDecodePara is set to <c>NULL</c>,
		/// then LocalAlloc and LocalFree are used to allocate and free memory. If pDecodePara points to a <c>CRYPT_DECODE_PARA</c>
		/// structure, that structure passes in callback functions to allocate and free memory. These callback functions override the
		/// default memory allocation of <c>LocalAlloc</c> and <c>LocalFree</c>.
		/// </param>
		/// <param name="pvStructInfo">
		/// <para>
		/// If the dwFlags CRYPT_ENCODE_ALLOC_FLAG is set, pvStructInfo is not a pointer to a buffer but is the address of a pointer to the
		/// buffer. Because memory is allocated inside the function and the pointer is stored at *pvStructInfo, pvStructInfo must never be <c>NULL</c>.
		/// </para>
		/// <para>
		/// If CRYPT_ENCODE_ALLOC_FLAG is not set, pvStructInfo is a pointer to a buffer that receives the decoded structure. When the
		/// buffer that is specified is not large enough to receive the decoded structure, the function sets the ERROR_MORE_DATA code and
		/// stores the required buffer size, in bytes, in the variable pointed to by pcbStructInfo.
		/// </para>
		/// <para>
		/// This parameter can be <c>NULL</c> to retrieve the size of this information for memory allocation purposes. For more information,
		/// see Retrieving Data of Unknown Length.
		/// </para>
		/// </param>
		/// <param name="pcbStructInfo">
		/// <para>
		/// A pointer to a <c>DWORD</c> variable that contains the size, in bytes, of the buffer pointed to by the pvStructInfo parameter.
		/// When the function returns, the <c>DWORD</c> value contains the number of bytes stored in the buffer. The size contained in the
		/// variable pointed to by pcbStructInfo can indicate a size larger than the decoded structure because the decoded structure can
		/// include pointers to auxiliary data. This size is the sum of the size needed by the decoded structure and the auxiliary data.
		/// </para>
		/// <para>
		/// When CRYPT_DECODE_ALLOC_FLAG is set, the initial value of *pcbStructInfo is not used by the function, and on return,
		/// *pcbStructInfo contains the number of bytes allocated for pvStructInfo.
		/// </para>
		/// <para>
		/// <c>Note</c> When processing the data returned in the buffer, applications must use the actual size of the data returned. The
		/// actual size can be slightly smaller than the size of the buffer specified on input. (On input, buffer sizes are usually
		/// specified large enough to ensure that the largest possible output data fits in the buffer.) On output, the variable pointed to
		/// by this parameter is updated to reflect the actual size of the data copied to the buffer.
		/// </para>
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, the function returns nonzero ( <c>TRUE</c>).</para>
		/// <para>
		/// If the function fails, it returns zero ( <c>FALSE</c>). For extended error information, call GetLastError. The following table
		/// shows some possible error codes.
		/// </para>
		/// <list type="table">
		/// <listheader>
		/// <term>Return code</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>CRYPT_E_BAD_ENCODE</term>
		/// <term>An error was encountered while decoding.</term>
		/// </item>
		/// <item>
		/// <term>ERROR_FILE_NOT_FOUND</term>
		/// <term>A decoding function could not be found for the specified dwCertEncodingType and lpszStructType.</term>
		/// </item>
		/// <item>
		/// <term>ERROR_MORE_DATA</term>
		/// <term>
		/// If the buffer specified by the pvStructInfo parameter is not large enough to hold the returned data, the function sets the
		/// ERROR_MORE_DATA code and stores the required buffer size, in bytes, in the variable pointed to by pcbStructInfo.
		/// </term>
		/// </item>
		/// </list>
		/// <para>
		/// If the function fails, GetLastError may return an Abstract Syntax Notation One (ASN.1) encoding/decoding error. For information
		/// about these errors, see ASN.1 Encoding/Decoding Return Values.
		/// </para>
		/// </returns>
		/// <remarks>
		/// <para>
		/// When encoding a cryptographic object using the preferred CryptEncodeObjectEx function, the terminating <c>NULL</c> character is
		/// included. When decoding, using the preferred <c>CryptDecodeObjectEx</c> function, the terminating <c>NULL</c> character is not retained.
		/// </para>
		/// <para>
		/// Each constant in the list below has an associated structure type that is pointed to by the pvStructInfo parameter. The structure
		/// pointed to, directly or indirectly, has a reference to a CERT_ALT_NAME_ENTRY structure.
		/// </para>
		/// <list type="bullet">
		/// <item>
		/// <term>X509_ALTERNATE_NAME</term>
		/// </item>
		/// <item>
		/// <term>szOID_AUTHORITY_INFO_ACCESS</term>
		/// </item>
		/// <item>
		/// <term>X509_AUTHORITY_INFO_ACCESS</term>
		/// </item>
		/// <item>
		/// <term>X509_AUTHORITY_KEY_ID2</term>
		/// </item>
		/// <item>
		/// <term>szOID_AUTHORITY_KEY_IDENTIFIER2</term>
		/// </item>
		/// <item>
		/// <term>szOID_CRL_DIST_POINTS</term>
		/// </item>
		/// <item>
		/// <term>X509_CRL_DIST_POINTS</term>
		/// </item>
		/// <item>
		/// <term>szOID_CROSS_CERT_DIST_POINTS</term>
		/// </item>
		/// <item>
		/// <term>X509_CROSS_CERT_DIST_POINTS</term>
		/// </item>
		/// <item>
		/// <term>szOID_ISSUER_ALT_NAME</term>
		/// </item>
		/// <item>
		/// <term>szOID_ISSUER_ALT_NAME2</term>
		/// </item>
		/// <item>
		/// <term>szOID_ISSUING_DIST_POINT</term>
		/// </item>
		/// <item>
		/// <term>X509_ISSUING_DIST_POINT</term>
		/// </item>
		/// <item>
		/// <term>X509_NAME_CONSTRAINTS</term>
		/// </item>
		/// <item>
		/// <term>szOID_NAME_CONSTRAINTS</term>
		/// </item>
		/// <item>
		/// <term>szOID_NEXT_UPDATE_LOCATION</term>
		/// </item>
		/// <item>
		/// <term>OCSP_REQUEST</term>
		/// </item>
		/// <item>
		/// <term>zOID_SUBJECT_ALT_NAME</term>
		/// </item>
		/// <item>
		/// <term>szOID_SUBJECT_ALT_NAME2</term>
		/// </item>
		/// </list>
		/// <para>
		/// The <c>CRYPT_DECODE_ENABLE_PUNYCODE_FLAG</c> flag, in conjunction with the value of the <c>dwAltNameChoice</c> member of the
		/// CERT_ALT_NAME_ENTRY structure, determines the manner in which strings are encoded.
		/// </para>
		/// <list type="table">
		/// <listheader>
		/// <term>dwAltNameChoice</term>
		/// <term>Effect</term>
		/// </listheader>
		/// <item>
		/// <term>CERT_ALT_NAME_DNS_NAME</term>
		/// <term>If the host name contains a Punycode encoded IA5String string, it is converted to the Unicode equivalent.</term>
		/// </item>
		/// <item>
		/// <term>CERT_ALT_NAME_RFC822_NAME</term>
		/// <term>
		/// If the host name portion of the email address contains a Punycode encoded IA5String string, it is converted to its Unicode equivalent.
		/// </term>
		/// </item>
		/// <item>
		/// <term>CERT_ALT_NAME_URL</term>
		/// <term>
		/// The URI is decoded. If the server host name of the URI contains a Punycode encoded IA5String string, the host name string is
		/// decoded to the Unicode equivalent.
		/// </term>
		/// </item>
		/// </list>
		/// <para>
		/// Each constant in the list below has an associated structure type that is pointed to by the pvStructInfo parameter. The structure
		/// pointed to, directly or indirectly, has a reference to a CERT_HASHED_URL structure.
		/// </para>
		/// <list type="bullet">
		/// <item>
		/// <term>szOID_LOGOTYPE_EXT</term>
		/// </item>
		/// <item>
		/// <term>X509_LOGOTYPE_EXT</term>
		/// </item>
		/// <item>
		/// <term>szOID_BIOMETRIC_EXT</term>
		/// </item>
		/// <item>
		/// <term>X509_BIOMETRIC_EXT</term>
		/// </item>
		/// </list>
		/// <para>
		/// When decoding the CERT_HASHED_URL structure value, the URI is decoded. If the host name contains a Punycode encoded host name,
		/// it is converted to the Unicode equivalent.
		/// </para>
		/// <para>
		/// Each <c>X509_UNICODE_NAME</c> constant in the list below has an associated structure type that is pointed to by the pvStructInfo parameter.
		/// </para>
		/// <list type="bullet">
		/// <item>
		/// <term>X509_UNICODE_NAME</term>
		/// </item>
		/// </list>
		/// <para>
		/// If the pszObjId member of the CERT_RDN_ATTR structure is set to <c>szOID_RSA_emailAddr</c> and the email address in the
		/// <c>Value</c> member contains Punycode encoded string, it is converted to the Unicode equivalent.
		/// </para>
		/// <para>Examples</para>
		/// <para>For an example that uses this function, see Example C Program: ASN.1 Encoding and Decoding.</para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptdecodeobjectex BOOL CryptDecodeObjectEx( DWORD
		// dwCertEncodingType, LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, PCRYPT_DECODE_PARA pDecodePara,
		// void *pvStructInfo, DWORD *pcbStructInfo );
		[DllImport(Lib.Crypt32, SetLastError = true, ExactSpelling = true)]
		[PInvokeData("wincrypt.h", MSDNShortId = "bf1935f0-1ab0-4068-9ed5-8fbb2c286b8a")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool CryptDecodeObjectEx(CertEncodingType dwCertEncodingType, [In] SafeOID lpszStructType, [In] IntPtr pbEncoded, uint cbEncoded,
			CryptDecodeFlags dwFlags, in CRYPT_DECODE_PARA pDecodePara, [Out] IntPtr pvStructInfo, ref uint pcbStructInfo);

		/// <summary>
		/// The <c>CryptDecodeObjectEx</c> function decodes a structure of the type indicated by the lpszStructType parameter.
		/// <c>CryptDecodeObjectEx</c> offers a significant performance improvement over CryptDecodeObject by supporting memory allocation
		/// with the CRYPT_DECODE_ALLOC_FLAG value.
		/// </summary>
		/// <param name="dwCertEncodingType">
		/// <para>
		/// The type of encoding used. It is always acceptable to specify both the certificate and message encoding types by combining them
		/// with a bitwise- <c>OR</c> operation as shown in the following example:
		/// </para>
		/// <para>X509_ASN_ENCODING | PKCS_7_ASN_ENCODING</para>
		/// <para>Currently defined encoding types are:</para>
		/// <list type="bullet">
		/// <item>
		/// <term>X509_ASN_ENCODING</term>
		/// </item>
		/// <item>
		/// <term>PKCS_7_ASN_ENCODING</term>
		/// </item>
		/// </list>
		/// <para>
		/// <c>Note</c> Either a certificate or message encoding type is required. X509_ASN_ENCODING is the default. If that type is
		/// indicated, it is used. Otherwise, if the PKCS7_ASN_ENCODING type is indicated, it is used.
		/// </para>
		/// </param>
		/// <param name="lpszStructType">
		/// <para>
		/// A pointer to an object identifier (OID) that defines the structure type. If the high-order word of the lpszStructType parameter
		/// is zero, the low-order word specifies the integer identifier for the type of the specified structure. Otherwise, this parameter
		/// is a long pointer to a null-terminated string.
		/// </para>
		/// <para>
		/// For more information about object identifier strings, their predefined constants, and corresponding structures, see Constants
		/// for CryptEncodeObject and CryptDecodeObject.
		/// </para>
		/// </param>
		/// <param name="pbEncoded">A pointer to the data to be decoded. The structure must be of the type specified by lpszStructType.</param>
		/// <param name="cbEncoded">The number of bytes pointed to by pbEncoded. This is the number of bytes to be decoded.</param>
		/// <param name="dwFlags">
		/// <para>This parameter can be one or more of the following flags. The flags can be combined by using a bitwise- <c>OR</c> operation.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>CRYPT_DECODE_ALLOC_FLAG</term>
		/// <term>
		/// The called decoding function allocates memory for the decoded structure. A pointer to the allocated structure is returned in
		/// pvStructInfo. If pDecodePara or the pfnAlloc member of pDecodePara is NULL, then LocalAlloc is called for the allocation and
		/// LocalFree must be called to free the memory. If pDecodePara and the pfnAlloc member of pDecodePara are not NULL, then the
		/// function pointed to by pfnAlloc is called for the allocation and the function pointed to by the pfnFree member of pDecodePara
		/// must be called to free the memory.
		/// </term>
		/// </item>
		/// <item>
		/// <term>CRYPT_DECODE_ENABLE_PUNYCODE_FLAG 33554432 (0x2000000)</term>
		/// <term>
		/// This flag is applicable for enabling Punycode decoding of Unicode string values. For more information, see Remarks. Windows
		/// Server 2008, Windows Vista, Windows Server 2003 and Windows XP: This flag is not supported.
		/// </term>
		/// </item>
		/// <item>
		/// <term>CRYPT_DECODE_NOCOPY_FLAG</term>
		/// <term>
		/// This flag can be set to enable a "no copy" optimization. This optimization updates the pvStructInfo members to point to content
		/// that resides within pbEncoded instead of making a copy of the content and appending it to pvStructInfo. The calling application
		/// needs to allocate less memory and execution is faster because a copy is not made. Note that when performing "no copy" decoding,
		/// pbEncoded cannot be freed until pvStructInfo is freed.
		/// </term>
		/// </item>
		/// <item>
		/// <term>CRYPT_UNICODE_NAME_DECODE_DISABLE_IE4_UTF8_FLAG</term>
		/// <term>
		/// This flag is applicable when decoding X509_UNICODE_NAME, X509_UNICODE_NAME_VALUE, or X509_UNICODE_ANY_STRING. By default,
		/// CERT_RDN_T61_STRING encoded values are initially decoded as UTF8. If the UTF8 decoding fails, then the value is decoded as
		/// eight-bit characters. If this flag is set, it skips the initial attempt to decode the value as UTF8 and decodes the value as
		/// eight-bit characters.
		/// </term>
		/// </item>
		/// <item>
		/// <term>CRYPT_DECODE_TO_BE_SIGNED_FLAG</term>
		/// <term>
		/// By default, the contents of the buffer pointed to by pbEncoded included the signed content and the signature. If this flag is
		/// set, the buffer includes only the "to be signed" content. This flag is applicable to X509_CERT_TO_BE_SIGNED,
		/// X509_CERT_CRL_TO_BE_SIGNED, X509_CRT_REQUEST_TO_BE_SIGNED, and X509_KEYGEN_REQUEST_TO_BE_SIGNED objects.
		/// </term>
		/// </item>
		/// <item>
		/// <term>CRYPT_DECODE_SHARE_OID_STRING_FLAG</term>
		/// <term>
		/// When this flag is set, the OID strings are allocated in Crypt32.dll and shared instead of being copied into the returned data
		/// structure. This flag can be set if Crypt32.dll is not unloaded before the caller is unloaded.
		/// </term>
		/// </item>
		/// <item>
		/// <term>CRYPT_DECODE_NO_SIGNATURE_BYTE_REVERSAL_FLAG</term>
		/// <term>By default, the signature bytes are reversed. If this flag is set, this byte reversal is inhibited.</term>
		/// </item>
		/// </list>
		/// </param>
		/// <param name="pDecodePara">
		/// A pointer to a CRYPT_DECODE_PARA structure that contains decoding paragraph information. If pDecodePara is set to <c>NULL</c>,
		/// then LocalAlloc and LocalFree are used to allocate and free memory. If pDecodePara points to a <c>CRYPT_DECODE_PARA</c>
		/// structure, that structure passes in callback functions to allocate and free memory. These callback functions override the
		/// default memory allocation of <c>LocalAlloc</c> and <c>LocalFree</c>.
		/// </param>
		/// <param name="pvStructInfo">
		/// <para>
		/// If the dwFlags CRYPT_ENCODE_ALLOC_FLAG is set, pvStructInfo is not a pointer to a buffer but is the address of a pointer to the
		/// buffer. Because memory is allocated inside the function and the pointer is stored at *pvStructInfo, pvStructInfo must never be <c>NULL</c>.
		/// </para>
		/// <para>
		/// If CRYPT_ENCODE_ALLOC_FLAG is not set, pvStructInfo is a pointer to a buffer that receives the decoded structure. When the
		/// buffer that is specified is not large enough to receive the decoded structure, the function sets the ERROR_MORE_DATA code and
		/// stores the required buffer size, in bytes, in the variable pointed to by pcbStructInfo.
		/// </para>
		/// <para>
		/// This parameter can be <c>NULL</c> to retrieve the size of this information for memory allocation purposes. For more information,
		/// see Retrieving Data of Unknown Length.
		/// </para>
		/// </param>
		/// <param name="pcbStructInfo">
		/// <para>
		/// A pointer to a <c>DWORD</c> variable that contains the size, in bytes, of the buffer pointed to by the pvStructInfo parameter.
		/// When the function returns, the <c>DWORD</c> value contains the number of bytes stored in the buffer. The size contained in the
		/// variable pointed to by pcbStructInfo can indicate a size larger than the decoded structure because the decoded structure can
		/// include pointers to auxiliary data. This size is the sum of the size needed by the decoded structure and the auxiliary data.
		/// </para>
		/// <para>
		/// When CRYPT_DECODE_ALLOC_FLAG is set, the initial value of *pcbStructInfo is not used by the function, and on return,
		/// *pcbStructInfo contains the number of bytes allocated for pvStructInfo.
		/// </para>
		/// <para>
		/// <c>Note</c> When processing the data returned in the buffer, applications must use the actual size of the data returned. The
		/// actual size can be slightly smaller than the size of the buffer specified on input. (On input, buffer sizes are usually
		/// specified large enough to ensure that the largest possible output data fits in the buffer.) On output, the variable pointed to
		/// by this parameter is updated to reflect the actual size of the data copied to the buffer.
		/// </para>
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, the function returns nonzero ( <c>TRUE</c>).</para>
		/// <para>
		/// If the function fails, it returns zero ( <c>FALSE</c>). For extended error information, call GetLastError. The following table
		/// shows some possible error codes.
		/// </para>
		/// <list type="table">
		/// <listheader>
		/// <term>Return code</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>CRYPT_E_BAD_ENCODE</term>
		/// <term>An error was encountered while decoding.</term>
		/// </item>
		/// <item>
		/// <term>ERROR_FILE_NOT_FOUND</term>
		/// <term>A decoding function could not be found for the specified dwCertEncodingType and lpszStructType.</term>
		/// </item>
		/// <item>
		/// <term>ERROR_MORE_DATA</term>
		/// <term>
		/// If the buffer specified by the pvStructInfo parameter is not large enough to hold the returned data, the function sets the
		/// ERROR_MORE_DATA code and stores the required buffer size, in bytes, in the variable pointed to by pcbStructInfo.
		/// </term>
		/// </item>
		/// </list>
		/// <para>
		/// If the function fails, GetLastError may return an Abstract Syntax Notation One (ASN.1) encoding/decoding error. For information
		/// about these errors, see ASN.1 Encoding/Decoding Return Values.
		/// </para>
		/// </returns>
		/// <remarks>
		/// <para>
		/// When encoding a cryptographic object using the preferred CryptEncodeObjectEx function, the terminating <c>NULL</c> character is
		/// included. When decoding, using the preferred <c>CryptDecodeObjectEx</c> function, the terminating <c>NULL</c> character is not retained.
		/// </para>
		/// <para>
		/// Each constant in the list below has an associated structure type that is pointed to by the pvStructInfo parameter. The structure
		/// pointed to, directly or indirectly, has a reference to a CERT_ALT_NAME_ENTRY structure.
		/// </para>
		/// <list type="bullet">
		/// <item>
		/// <term>X509_ALTERNATE_NAME</term>
		/// </item>
		/// <item>
		/// <term>szOID_AUTHORITY_INFO_ACCESS</term>
		/// </item>
		/// <item>
		/// <term>X509_AUTHORITY_INFO_ACCESS</term>
		/// </item>
		/// <item>
		/// <term>X509_AUTHORITY_KEY_ID2</term>
		/// </item>
		/// <item>
		/// <term>szOID_AUTHORITY_KEY_IDENTIFIER2</term>
		/// </item>
		/// <item>
		/// <term>szOID_CRL_DIST_POINTS</term>
		/// </item>
		/// <item>
		/// <term>X509_CRL_DIST_POINTS</term>
		/// </item>
		/// <item>
		/// <term>szOID_CROSS_CERT_DIST_POINTS</term>
		/// </item>
		/// <item>
		/// <term>X509_CROSS_CERT_DIST_POINTS</term>
		/// </item>
		/// <item>
		/// <term>szOID_ISSUER_ALT_NAME</term>
		/// </item>
		/// <item>
		/// <term>szOID_ISSUER_ALT_NAME2</term>
		/// </item>
		/// <item>
		/// <term>szOID_ISSUING_DIST_POINT</term>
		/// </item>
		/// <item>
		/// <term>X509_ISSUING_DIST_POINT</term>
		/// </item>
		/// <item>
		/// <term>X509_NAME_CONSTRAINTS</term>
		/// </item>
		/// <item>
		/// <term>szOID_NAME_CONSTRAINTS</term>
		/// </item>
		/// <item>
		/// <term>szOID_NEXT_UPDATE_LOCATION</term>
		/// </item>
		/// <item>
		/// <term>OCSP_REQUEST</term>
		/// </item>
		/// <item>
		/// <term>zOID_SUBJECT_ALT_NAME</term>
		/// </item>
		/// <item>
		/// <term>szOID_SUBJECT_ALT_NAME2</term>
		/// </item>
		/// </list>
		/// <para>
		/// The <c>CRYPT_DECODE_ENABLE_PUNYCODE_FLAG</c> flag, in conjunction with the value of the <c>dwAltNameChoice</c> member of the
		/// CERT_ALT_NAME_ENTRY structure, determines the manner in which strings are encoded.
		/// </para>
		/// <list type="table">
		/// <listheader>
		/// <term>dwAltNameChoice</term>
		/// <term>Effect</term>
		/// </listheader>
		/// <item>
		/// <term>CERT_ALT_NAME_DNS_NAME</term>
		/// <term>If the host name contains a Punycode encoded IA5String string, it is converted to the Unicode equivalent.</term>
		/// </item>
		/// <item>
		/// <term>CERT_ALT_NAME_RFC822_NAME</term>
		/// <term>
		/// If the host name portion of the email address contains a Punycode encoded IA5String string, it is converted to its Unicode equivalent.
		/// </term>
		/// </item>
		/// <item>
		/// <term>CERT_ALT_NAME_URL</term>
		/// <term>
		/// The URI is decoded. If the server host name of the URI contains a Punycode encoded IA5String string, the host name string is
		/// decoded to the Unicode equivalent.
		/// </term>
		/// </item>
		/// </list>
		/// <para>
		/// Each constant in the list below has an associated structure type that is pointed to by the pvStructInfo parameter. The structure
		/// pointed to, directly or indirectly, has a reference to a CERT_HASHED_URL structure.
		/// </para>
		/// <list type="bullet">
		/// <item>
		/// <term>szOID_LOGOTYPE_EXT</term>
		/// </item>
		/// <item>
		/// <term>X509_LOGOTYPE_EXT</term>
		/// </item>
		/// <item>
		/// <term>szOID_BIOMETRIC_EXT</term>
		/// </item>
		/// <item>
		/// <term>X509_BIOMETRIC_EXT</term>
		/// </item>
		/// </list>
		/// <para>
		/// When decoding the CERT_HASHED_URL structure value, the URI is decoded. If the host name contains a Punycode encoded host name,
		/// it is converted to the Unicode equivalent.
		/// </para>
		/// <para>
		/// Each <c>X509_UNICODE_NAME</c> constant in the list below has an associated structure type that is pointed to by the pvStructInfo parameter.
		/// </para>
		/// <list type="bullet">
		/// <item>
		/// <term>X509_UNICODE_NAME</term>
		/// </item>
		/// </list>
		/// <para>
		/// If the pszObjId member of the CERT_RDN_ATTR structure is set to <c>szOID_RSA_emailAddr</c> and the email address in the
		/// <c>Value</c> member contains Punycode encoded string, it is converted to the Unicode equivalent.
		/// </para>
		/// <para>Examples</para>
		/// <para>For an example that uses this function, see Example C Program: ASN.1 Encoding and Decoding.</para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptdecodeobjectex BOOL CryptDecodeObjectEx( DWORD
		// dwCertEncodingType, LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, PCRYPT_DECODE_PARA pDecodePara,
		// void *pvStructInfo, DWORD *pcbStructInfo );
		[DllImport(Lib.Crypt32, SetLastError = true, ExactSpelling = true)]
		[PInvokeData("wincrypt.h", MSDNShortId = "bf1935f0-1ab0-4068-9ed5-8fbb2c286b8a")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool CryptDecodeObjectEx(CertEncodingType dwCertEncodingType, [In] SafeOID lpszStructType, [In] IntPtr pbEncoded, uint cbEncoded,
			CryptDecodeFlags dwFlags, [In, Optional] IntPtr pDecodePara, [Out] IntPtr pvStructInfo, ref uint pcbStructInfo);

		/// <summary>
		/// The <c>CryptEncodeObject</c> function encodes a structure of the type indicated by the value of the lpszStructType parameter.
		/// The use of CryptEncodeObjectEx is recommended as an API that performs the same function with significant performance improvements.
		/// </summary>
		/// <param name="dwCertEncodingType">
		/// <para>
		/// Type of encoding used. It is always acceptable to specify both the certificate and message encoding types by combining them with
		/// a bitwise- <c>OR</c> operation as shown in the following example:
		/// </para>
		/// <para>X509_ASN_ENCODING | PKCS_7_ASN_ENCODING</para>
		/// <para>Currently defined encoding types are:</para>
		/// <list type="bullet">
		/// <item>
		/// <term>X509_ASN_ENCODING</term>
		/// </item>
		/// <item>
		/// <term>PKCS_7_ASN_ENCODING</term>
		/// </item>
		/// </list>
		/// <para>
		/// <c>Note</c> Either a certificate or message encoding type is required. X509_ASN_ENCODING is the default. If that type is
		/// indicated, it is used. Otherwise, if the PKCS7_ASN_ENCODING type is indicated, it is used.
		/// </para>
		/// </param>
		/// <param name="lpszStructType">
		/// <para>
		/// A pointer to an OID defining the structure type. If the high-order word of the lpszStructType parameter is zero, the low-order
		/// word specifies the integer identifier for the type of the specified structure. Otherwise, this parameter is a long pointer to a
		/// null-terminated string.
		/// </para>
		/// <para>
		/// For more information about object identifier strings, their predefined constants and corresponding structures, see Constants for
		/// CryptEncodeObject and CryptDecodeObject.
		/// </para>
		/// </param>
		/// <param name="pvStructInfo">A pointer to the structure to be encoded. The structure must be of a type specified by lpszStructType.</param>
		/// <param name="pbEncoded">
		/// <para>
		/// A pointer to a buffer to receive the encoded structure. When the buffer that is specified is not large enough to receive the
		/// decoded structure, the function sets the ERROR_MORE_DATA code and stores the required buffer size, in bytes, in the variable
		/// pointed to by pcbEncoded.
		/// </para>
		/// <para>
		/// This parameter can be <c>NULL</c> to retrieve the size of this information for memory allocation purposes. For more information,
		/// see Retrieving Data of Unknown Length.
		/// </para>
		/// </param>
		/// <param name="pcbEncoded">
		/// <para>
		/// A pointer to a <c>DWORD</c> variable that contains the size, in bytes, of the buffer pointed to by the pbEncoded parameter. When
		/// the function returns, the <c>DWORD</c> value contains the number of allocated encoded bytes stored in the buffer.
		/// </para>
		/// <para>
		/// <c>Note</c> When processing the data returned in the buffer, applications must use the actual size of the data returned. The
		/// actual size can be slightly smaller than the size of the buffer specified on input. (On input, buffer sizes are usually
		/// specified large enough to ensure that the largest possible output data fits in the buffer.) On output, the variable pointed to
		/// by this parameter is updated to reflect the actual size of the data copied to the buffer.
		/// </para>
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, the return value is nonzero ( <c>TRUE</c>).</para>
		/// <para>
		/// If the function fails, the return value is zero ( <c>FALSE</c>). For extended error information, call GetLastError. Some
		/// possible error codes are listed in the following table.
		/// </para>
		/// <list type="table">
		/// <listheader>
		/// <term>Return code</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>CRYPT_E_BAD_ENCODE</term>
		/// <term>An error was encountered while encoding.</term>
		/// </item>
		/// <item>
		/// <term>ERROR_FILE_NOT_FOUND</term>
		/// <term>An encoding function could not be found for the specified dwCertEncodingType and lpszStructType.</term>
		/// </item>
		/// <item>
		/// <term>ERROR_MORE_DATA</term>
		/// <term>
		/// If the buffer specified by the pbEncoded parameter is not large enough to hold the returned data, the function sets the
		/// ERROR_MORE_DATA code and stores the required buffer size, in bytes, in the variable pointed to by pcbEncoded.
		/// </term>
		/// </item>
		/// </list>
		/// <para>
		/// If the function fails, GetLastError may return an Abstract Syntax Notation One (ASN.1) encoding/decoding error. For information
		/// about these errors, see ASN.1 Encoding/Decoding Return Values.
		/// </para>
		/// </returns>
		/// <remarks>
		/// <para>
		/// When encoding a cryptographic object using the preferred CryptEncodeObjectEx function, the terminating <c>NULL</c> character is
		/// included. When decoding, using the preferred CryptDecodeObjectEx function, the terminating <c>NULL</c> character is not retained.
		/// </para>
		/// <para>Examples</para>
		/// <para>
		/// For an example that uses this function, see Example C Program: Making a Certificate Request and Example C Program: ASN.1
		/// Encoding and Decoding.
		/// </para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptencodeobject BOOL CryptEncodeObject( DWORD
		// dwCertEncodingType, LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded, DWORD *pcbEncoded );
		[DllImport(Lib.Crypt32, SetLastError = true, ExactSpelling = true)]
		[PInvokeData("wincrypt.h", MSDNShortId = "9576a2a7-4379-4c1b-8ad5-284720cf7ccc")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool CryptEncodeObject(CertEncodingType dwCertEncodingType, [In] SafeOID lpszStructType, [In] IntPtr pvStructInfo, [Out] IntPtr pbEncoded, ref uint pcbEncoded);

		/// <summary>
		/// The <c>CryptEncodeObjectEx</c> function encodes a structure of the type indicated by the value of the lpszStructType parameter.
		/// This function offers a significant performance improvement over CryptEncodeObject by supporting memory allocation with the
		/// <c>CRYPT_ENCODE_ALLOC_FLAG</c> value.
		/// </summary>
		/// <param name="dwCertEncodingType">
		/// <para>
		/// The certificate encoding type and message encoding type to use to encode the object. This parameter can be a combination of one
		/// or more of the following values.
		/// </para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>PKCS_7_ASN_ENCODING 65536 (0x10000)</term>
		/// <term>Specifies PKCS 7 message encoding.</term>
		/// </item>
		/// <item>
		/// <term>X509_ASN_ENCODING 1 (0x1)</term>
		/// <term>Specifies X.509 certificate encoding.</term>
		/// </item>
		/// </list>
		/// </param>
		/// <param name="lpszStructType">
		/// <para>
		/// A pointer to an object identifier (OID) that defines the structure type. If the high-order word of the lpszStructType parameter
		/// is zero, the low-order word specifies an integer identifier for the type of the specified structure. Otherwise, this parameter
		/// is a pointer to a null-terminated string that contains the string representation of the OID.
		/// </para>
		/// <para>
		/// For more information about object identifier strings, their predefined constants and corresponding structures, see Constants for
		/// CryptEncodeObject and CryptDecodeObject.
		/// </para>
		/// </param>
		/// <param name="pvStructInfo">A pointer to the structure to be encoded. The structure must be of the type specified by lpszStructType.</param>
		/// <param name="dwFlags">
		/// <para>Specifies options for the encoding. This parameter can be zero or a combination of one or more of the following values.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>CRYPT_ENCODE_ALLOC_FLAG 32768 (0x8000)</term>
		/// <term>The called encoding function allocates memory for the encoded bytes. A pointer to the allocated bytes is returned in pvEncoded.</term>
		/// </item>
		/// <item>
		/// <term>CRYPT_ENCODE_ENABLE_PUNYCODE_FLAG 131072 (0x20000)</term>
		/// <term>
		/// This flag is applicable for enabling Punycode encoding of Unicode string values. For more information, see Remarks. Windows
		/// Server 2008, Windows Vista, Windows Server 2003 and Windows XP: This flag is not supported.
		/// </term>
		/// </item>
		/// <item>
		/// <term>CRYPT_UNICODE_NAME_ENCODE_DISABLE_CHECK_TYPE_FLAG 1073741824 (0x40000000)</term>
		/// <term>
		/// This flag is applicable when encoding X509_UNICODE_NAME, X509_UNICODE_NAME_VALUE, or X509_UNICODE_ANY_STRING. If this flag is
		/// set, the characters are not checked to determine whether they are valid for the specified value type.
		/// </term>
		/// </item>
		/// <item>
		/// <term>CRYPT_UNICODE_NAME_ENCODE_ENABLE_T61_UNICODE_FLAG 2147483648 (0x80000000)</term>
		/// <term>
		/// This flag is applicable when encoding X509_UNICODE_NAME. If this flag is set and all the Unicode characters are &lt;= 0xFF, the
		/// CERT_RDN_T61_STRING is selected instead of the CERT_RDN_UNICODE_STRING.
		/// </term>
		/// </item>
		/// <item>
		/// <term>CRYPT_UNICODE_NAME_ENCODE_ENABLE_UTF8_UNICODE_FLAG 536870912 (0x20000000)</term>
		/// <term>This flag is applicable when encoding an X509_UNICODE_NAME. When set, CERT_RDN_UTF8_STRING is selected instead of CERT_RDN_UNICODE_STRING.</term>
		/// </item>
		/// <item>
		/// <term>CRYPT_UNICODE_NAME_ENCODE_FORCE_UTF8_UNICODE_FLAG 268435456 (0x10000000)</term>
		/// <term>
		/// This flag is applicable when encoding an X509_UNICODE_NAME. When set, CERT_RDN_UTF8_STRING is selected instead of
		/// CERT_RDN_PRINTABLE_STRING for directory string types. Also, this flag enables CRYPT_UNICODE_NAME_ENCODE_ENABLE_UTF8_UNICODE_FLAG.
		/// </term>
		/// </item>
		/// </list>
		/// </param>
		/// <param name="pEncodePara">
		/// <para>A pointer to a CRYPT_ENCODE_PARA structure that contains encoding information. This parameter can be <c>NULL</c>.</para>
		/// <para>
		/// If either pEncodePara or the <c>pfnAlloc</c> member of pEncodePara is <c>NULL</c>, then LocalAlloc is used for the allocation
		/// and LocalFree must be called to free the memory.
		/// </para>
		/// <para>
		/// If both pEncodePara and the <c>pfnAlloc</c> member of pEncodePara are not <c>NULL</c>, then the function pointed to by the
		/// <c>pfnAlloc</c> member of the CRYPT_ENCODE_PARA structure pointed to by pEncodePara is called for the allocation. The function
		/// pointed to by the <c>pfnFree</c> member of pEncodePara must be called to free the memory.
		/// </para>
		/// </param>
		/// <param name="pvEncoded">
		/// <para>
		/// A pointer to a buffer to receive the encoded structure. The size of this buffer is specified in the pcbEncoded parameter. When
		/// the buffer that is specified is not large enough to receive the decoded structure, the function sets the <c>ERROR_MORE_DATA</c>
		/// code and stores the required buffer size, in bytes, in the variable pointed to by pcbEncoded.
		/// </para>
		/// <para>
		/// This parameter can be <c>NULL</c> to retrieve the size of the buffer for memory allocation purposes. For more information, see
		/// Retrieving Data of Unknown Length.
		/// </para>
		/// <para>
		/// If dwFlags contains the <c>CRYPT_ENCODE_ALLOC_FLAG</c> flag, pvEncoded is not a pointer to a buffer but is the address of a
		/// pointer to the buffer. Because memory is allocated inside the function and the pointer is stored in pvEncoded, pvEncoded cannot
		/// be <c>NULL</c>.
		/// </para>
		/// </param>
		/// <param name="pcbEncoded">
		/// <para>
		/// A pointer to a <c>DWORD</c> variable that contains the size, in bytes, of the buffer pointed to by the pvEncoded parameter. When
		/// the function returns, the variable pointed to by the pcbEncoded parameter contains the number of allocated, encoded bytes stored
		/// in the buffer.
		/// </para>
		/// <para>
		/// When dwFlags contains the <c>CRYPT_ENCODE_ALLOC_FLAG</c> flag, pcbEncoded is the address of a pointer to the <c>DWORD</c> value
		/// that is updated.
		/// </para>
		/// <para>
		/// <c>Note</c> When processing the data returned in the buffer, applications must use the actual size of the data returned. The
		/// actual size can be slightly smaller than the size of the buffer specified on input. (On input, buffer sizes are usually
		/// specified large enough to ensure that the largest possible output data fits in the buffer.) On output, the variable pointed to
		/// by this parameter is updated to reflect the actual size of the data copied to the buffer.
		/// </para>
		/// </param>
		/// <returns>
		/// <para>Returns nonzero if successful or zero otherwise.</para>
		/// <para>
		/// For extended error information, call GetLastError. The following table shows some possible error codes that can be returned from
		/// <c>GetLastError</c> when <c>CryptEncodeObjectEx</c> fails.
		/// </para>
		/// <list type="table">
		/// <listheader>
		/// <term>Return code</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>CRYPT_E_BAD_ENCODE</term>
		/// <term>An error was encountered while encoding.</term>
		/// </item>
		/// <item>
		/// <term>ERROR_FILE_NOT_FOUND</term>
		/// <term>An encoding function could not be found for the specified dwCertEncodingType and lpszStructType.</term>
		/// </item>
		/// <item>
		/// <term>ERROR_MORE_DATA</term>
		/// <term>
		/// If the buffer specified by the pvEncoded parameter is not large enough to hold the returned data, the function sets the
		/// ERROR_MORE_DATA code and stores the required buffer size, in bytes, in the variable pointed to by pcbEncoded.
		/// </term>
		/// </item>
		/// </list>
		/// <para>
		/// If the function fails, GetLastError may return an Abstract Syntax Notation One (ASN.1) encoding/decoding error. For information
		/// about these errors, see ASN.1 Encoding/Decoding Return Values.
		/// </para>
		/// </returns>
		/// <remarks>
		/// <para>
		/// When encoding a cryptographic object using the preferred <c>CryptEncodeObjectEx</c> function, the terminating <c>NULL</c>
		/// character is included. When decoding, using the preferred CryptDecodeObjectEx function, the terminating <c>NULL</c> character is
		/// not retained.
		/// </para>
		/// <para>
		/// <c>CryptEncodeObjectEx</c> first looks for an installable extended encoding function. If no extended encoding function is found,
		/// the old, nonextended, installable function is located.
		/// </para>
		/// <para>
		/// When direct IA5String encoding of the object is not possible, you can specify Punycode encoding by setting the dwFlag parameter
		/// to the <c>CRYPT_ENCODE_ENABLE_PUNYCODE_FLAG</c> value. Setting the <c>CRYPT_ENCODE_ENABLE_PUNYCODE_FLAG</c> flag has different
		/// effects based on the structure type being encoded as specified by the value of the lpszStructType parameter.
		/// </para>
		/// <para>
		/// Each constant in the list below has an associated structure type that is pointed to by the pvStructInfo parameter. The structure
		/// pointed to, directly or indirectly, has a reference to a CERT_ALT_NAME_ENTRY structure.
		/// </para>
		/// <list type="bullet">
		/// <item>
		/// <term>X509_ALTERNATE_NAME</term>
		/// </item>
		/// <item>
		/// <term>szOID_AUTHORITY_INFO_ACCESS</term>
		/// </item>
		/// <item>
		/// <term>X509_AUTHORITY_INFO_ACCESS</term>
		/// </item>
		/// <item>
		/// <term>X509_AUTHORITY_KEY_ID2</term>
		/// </item>
		/// <item>
		/// <term>szOID_AUTHORITY_KEY_IDENTIFIER2</term>
		/// </item>
		/// <item>
		/// <term>szOID_CRL_DIST_POINTS</term>
		/// </item>
		/// <item>
		/// <term>X509_CRL_DIST_POINTS</term>
		/// </item>
		/// <item>
		/// <term>szOID_CROSS_CERT_DIST_POINTS</term>
		/// </item>
		/// <item>
		/// <term>X509_CROSS_CERT_DIST_POINTS</term>
		/// </item>
		/// <item>
		/// <term>szOID_ISSUER_ALT_NAME</term>
		/// </item>
		/// <item>
		/// <term>szOID_ISSUER_ALT_NAME2</term>
		/// </item>
		/// <item>
		/// <term>szOID_ISSUING_DIST_POINT</term>
		/// </item>
		/// <item>
		/// <term>X509_ISSUING_DIST_POINT</term>
		/// </item>
		/// <item>
		/// <term>szOID_NAME_CONSTRAINTS</term>
		/// </item>
		/// <item>
		/// <term>X509_NAME_CONSTRAINTS</term>
		/// </item>
		/// <item>
		/// <term>szOID_NEXT_UPDATE_LOCATION</term>
		/// </item>
		/// <item>
		/// <term>OCSP_REQUEST</term>
		/// </item>
		/// <item>
		/// <term>zOID_SUBJECT_ALT_NAME</term>
		/// </item>
		/// <item>
		/// <term>szOID_SUBJECT_ALT_NAME2</term>
		/// </item>
		/// </list>
		/// <para>
		/// The <c>CRYPT_ENCODE_ENABLE_PUNYCODE_FLAG</c> flag, in conjunction with the value of the <c>dwAltNameChoice</c> member of the
		/// CERT_ALT_NAME_ENTRY structure, determines the manner in which strings are encoded.
		/// </para>
		/// <list type="table">
		/// <listheader>
		/// <term>dwAltNameChoice</term>
		/// <term>Effect</term>
		/// </listheader>
		/// <item>
		/// <term>CERT_ALT_NAME_DNS_NAME</term>
		/// <term>
		/// If the host name contains Unicode characters outside of the ASCII character set, the host name is first encoded in Punycode and
		/// then encoded as an IA5String string.
		/// </term>
		/// </item>
		/// <item>
		/// <term>CERT_ALT_NAME_RFC822_NAME</term>
		/// <term>
		/// If the host name portion of the email address contains Unicode characters outside of the ASCII character set, the host name
		/// portion of the email address is encoded in Punycode. The resultant email address is then encoded as an IA5String string.
		/// </term>
		/// </item>
		/// <item>
		/// <term>CERT_ALT_NAME_URL</term>
		/// <term>
		/// If the server host name of the URI contains Unicode characters outside of the ASCII character set, then the host name portion of
		/// URI is encoded in Punycode. Then the resultant URI is escaped, and the URL is then encoded as an IA5String string.
		/// </term>
		/// </item>
		/// </list>
		/// <para>
		/// Each constant in the list below has an associated structure type that is pointed to by the pvStructInfo parameter. The structure
		/// pointed to, directly or indirectly, has a reference to a CERT_HASHED_URL structure.
		/// </para>
		/// <list type="bullet">
		/// <item>
		/// <term>szOID_BIOMETRIC_EXT</term>
		/// </item>
		/// <item>
		/// <term>X509_BIOMETRIC_EXT</term>
		/// </item>
		/// <item>
		/// <term>szOID_LOGOTYPE_EXT</term>
		/// </item>
		/// <item>
		/// <term>X509_LOGOTYPE_EXT</term>
		/// </item>
		/// </list>
		/// <para>
		/// When encoding the CERT_HASHED_URL structure value, if the server host name of the URI contains Unicode characters outside of the
		/// ASCII character set, and the <c>CRYPT_ENCODE_ENABLE_PUNYCODE_FLAG</c> is set, the host name portion of URI is encoded in
		/// Punycode. Then the resultant URI is escaped, and the URL is then encoded as an IA5String string.
		/// </para>
		/// <para>
		/// Each <c>X509_UNICODE_NAME</c> constant in the list below has an associated structure type that is pointed to by the pvStructInfo parameter.
		/// </para>
		/// <list type="bullet">
		/// <item>
		/// <term>X509_UNICODE_NAME</term>
		/// </item>
		/// </list>
		/// <para>
		/// If the pszObjId member of the CERT_RDN_ATTR structure is set to <c>szOID_RSA_emailAddr</c> and the email address in the
		/// <c>Value</c> member contains Unicode characters outside of the ASCII character set, the host name portion of the email address
		/// is encoded in Punycode. Then the resultant email address is then encoded as an IA5String string.
		/// </para>
		/// <para>In all cases, the Punycode encoding of the host name is performed on a label-by-label basis.</para>
		/// <para>Examples</para>
		/// <para>
		/// The following example shows initializing and encoding an X509_NAME structure using <c>CryptEncodeObjectEx</c>. For an example
		/// that includes the complete context for this example, see Example C Program: ASN.1 Encoding and Decoding.
		/// </para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptencodeobjectex BOOL CryptEncodeObjectEx( DWORD
		// dwCertEncodingType, LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, void
		// *pvEncoded, DWORD *pcbEncoded );
		[DllImport(Lib.Crypt32, SetLastError = true, ExactSpelling = true)]
		[PInvokeData("wincrypt.h", MSDNShortId = "45134db8-059b-43d3-90c2-9b6cc970fca0")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool CryptEncodeObjectEx(CertEncodingType dwCertEncodingType, [In] SafeOID lpszStructType, [In] IntPtr pvStructInfo,
			CryptEncodeFlags dwFlags, in CRYPT_ENCODE_PARA pEncodePara, [Out] IntPtr pvEncoded, ref uint pcbEncoded);

		/// <summary>
		/// The <c>CRYPT_DECODE_PARA</c> structure is used by the CryptDecodeObjectEx function to provide access to memory allocation and
		/// memory freeing callback functions.
		/// </summary>
		// https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/ns-wincrypt-crypt_decode_para typedef struct _CRYPT_DECODE_PARA {
		// DWORD cbSize; PFN_CRYPT_ALLOC pfnAlloc; PFN_CRYPT_FREE pfnFree; } CRYPT_DECODE_PARA, *PCRYPT_DECODE_PARA;
		[PInvokeData("wincrypt.h", MSDNShortId = "08ed4627-8cbf-415f-b0d0-2c4b9ed9aed1")]
		[StructLayout(LayoutKind.Sequential)]
		public struct CRYPT_DECODE_PARA
		{
			/// <summary>The size, in bytes, of this structure.</summary>
			public uint cbSize;

			/// <summary>This member is an optional pointer to a callback function used to allocate memory.</summary>
			[MarshalAs(UnmanagedType.FunctionPtr)]
			public PFN_CRYPT_ALLOC pfnAlloc;

			/// <summary>
			/// This member is an optional pointer to a callback function used to free memory allocated by the allocate callback function.
			/// </summary>
			[MarshalAs(UnmanagedType.FunctionPtr)]
			public PFN_CRYPT_FREE pfnFree;

			/// <summary>Gets an instance which uses the CoTaskMem... methods for allocating and freeing memory.</summary>
			public static readonly CRYPT_DECODE_PARA CoTaskMemInstance = new CRYPT_DECODE_PARA { cbSize = (uint)Marshal.SizeOf(typeof(CRYPT_DECODE_PARA)), pfnAlloc = s => Marshal.AllocCoTaskMem(s), pfnFree = Marshal.FreeCoTaskMem };
		}

		/// <summary>
		/// The <c>CRYPT_ENCODE_PARA</c> structure is used by the CryptEncodeObjectEx function to provide access to memory allocation and
		/// memory freeing callback functions.
		/// </summary>
		// https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/ns-wincrypt-crypt_encode_para typedef struct _CRYPT_ENCODE_PARA {
		// DWORD cbSize; PFN_CRYPT_ALLOC pfnAlloc; PFN_CRYPT_FREE pfnFree; } CRYPT_ENCODE_PARA, *PCRYPT_ENCODE_PARA;
		[PInvokeData("wincrypt.h", MSDNShortId = "330af6ac-f1db-4cee-81fd-d3c2c341d493")]
		[StructLayout(LayoutKind.Sequential)]
		public struct CRYPT_ENCODE_PARA
		{
			/// <summary>The size, in bytes, of this structure.</summary>
			public uint cbSize;

			/// <summary>This member is an optional pointer to a callback function used to allocate memory.</summary>
			[MarshalAs(UnmanagedType.FunctionPtr)]
			public PFN_CRYPT_ALLOC pfnAlloc;

			/// <summary>
			/// This member is an optional pointer to a callback function used to free memory allocated by the allocate callback function.
			/// </summary>
			[MarshalAs(UnmanagedType.FunctionPtr)]
			public PFN_CRYPT_FREE pfnFree;

			/// <summary>Gets an instance which uses the CoTaskMem... methods for allocating and freeing memory.</summary>
			public static readonly CRYPT_ENCODE_PARA CoTaskMemInstance = new CRYPT_ENCODE_PARA { cbSize = (uint)Marshal.SizeOf(typeof(CRYPT_ENCODE_PARA)), pfnAlloc = s => Marshal.AllocCoTaskMem(s), pfnFree = Marshal.FreeCoTaskMem };
		}
	}
}