using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using Vanara.Extensions;
using Vanara.InteropServices;
using static Vanara.PInvoke.Ws2_32;
using DNS_STATUS = Vanara.PInvoke.Win32Error;
using IP4_ADDRESS = Vanara.PInvoke.Ws2_32.IN_ADDR;
using IP6_ADDRESS = Vanara.PInvoke.Ws2_32.IN6_ADDR;

namespace Vanara.PInvoke
{
	/// <summary>Functions, structures and constants from windns.h.</summary>
	public static partial class DnsApi
	{
		/// <summary>The <c>DNS_QUERY_COMPLETION_ROUTINE</c> callback is used to asynchronously return the results of a DNS query.</summary>
		/// <param name="pQueryContext">A pointer to a user context.</param>
		/// <param name="pQueryResults">A pointer to a DNS_QUERY_RESULT structure that contains the DNS query results from a call to DnsQueryEx.</param>
		/// <returns>None</returns>
		// https://docs.microsoft.com/en-us/windows/win32/api/windns/nc-windns-dns_query_completion_routine DNS_QUERY_COMPLETION_ROUTINE
		// DnsQueryCompletionRoutine; void DnsQueryCompletionRoutine( PVOID pQueryContext, PDNS_QUERY_RESULT pQueryResults ) {...}
		[PInvokeData("windns.h", MSDNShortId = "35D78208-FFC1-48B0-8267-EE583DE2D783")]
		[UnmanagedFunctionPointer(CallingConvention.Winapi)]
		public delegate void DNS_QUERY_COMPLETION_ROUTINE([In] IntPtr pQueryContext, ref DNS_QUERY_RESULT pQueryResults);

		/// <summary>Used to asynchronously return the results of a DNS-SD query.</summary>
		/// <param name="Status">A value that contains the status associated with this particular set of results.</param>
		/// <param name="pQueryContext">A pointer to the user context that was passed to DnsServiceBrowse.</param>
		/// <param name="pDnsRecord">
		/// A pointer to a DNS_RECORD structure that contains a list of records describing a discovered service on the network. If not ,
		/// then you are responsible for freeing the returned RR sets using DnsRecordListFree.
		/// </param>
		/// <returns>None</returns>
		// https://docs.microsoft.com/en-us/windows/win32/api/windns/nc-windns-dns_service_browse_callback DNS_SERVICE_BROWSE_CALLBACK
		// DnsServiceBrowseCallback; void DnsServiceBrowseCallback( DWORD Status, PVOID pQueryContext, PDNS_RECORD pDnsRecord ) {...}
		[PInvokeData("windns.h")]
		[UnmanagedFunctionPointer(CallingConvention.Winapi)]
		public delegate void DNS_SERVICE_BROWSE_CALLBACK(uint Status, [In] IntPtr pQueryContext, IntPtr pDnsRecord);

		/// <summary>Used to notify your application that service registration has completed.</summary>
		/// <param name="Status">A value that contains the status of the registration.</param>
		/// <param name="pQueryContext">A pointer to the user context that was passed to DnsServiceRegister.</param>
		/// <param name="pInstance">
		/// A pointer to a DNS_SERVICE_INSTANCE structure that describes the service that was registered. If not , then you are responsible
		/// for freeing the data using DnsServiceFreeInstance.
		/// </param>
		/// <returns>None</returns>
		// https://docs.microsoft.com/en-us/windows/win32/api/windns/nc-windns-dns_service_register_complete DNS_SERVICE_REGISTER_COMPLETE
		// DnsServiceRegisterComplete; void DnsServiceRegisterComplete( DWORD Status, PVOID pQueryContext, PDNS_SERVICE_INSTANCE pInstance ) {...}
		[PInvokeData("windns.h")]
		[UnmanagedFunctionPointer(CallingConvention.Winapi)]
		public delegate void DNS_SERVICE_REGISTER_COMPLETE(uint Status, [In] IntPtr pQueryContext, [In] IntPtr pInstance);

		/// <summary>Used to asynchronously return the results of a service resolve operation.</summary>
		/// <param name="Status">A value that contains the status associated with this particular set of results.</param>
		/// <param name="pQueryContext">A pointer to the user context that was passed to DnsServiceResolve.</param>
		/// <param name="pInstance">
		/// A pointer to a DNS_SERVICE_INSTANCE structure that contains detailed information about a service on the network. If not , then
		/// you are responsible for freeing the data using DnsServiceFreeInstance.
		/// </param>
		/// <returns>None</returns>
		// https://docs.microsoft.com/en-us/windows/win32/api/windns/nc-windns-dns_service_resolve_complete DNS_SERVICE_RESOLVE_COMPLETE
		// DnsServiceResolveComplete; void DnsServiceResolveComplete( DWORD Status, PVOID pQueryContext, PDNS_SERVICE_INSTANCE pInstance ) {...}
		[PInvokeData("windns.h")]
		[UnmanagedFunctionPointer(CallingConvention.Winapi)]
		public delegate void DNS_SERVICE_RESOLVE_COMPLETE(uint Status, [In] IntPtr pQueryContext, [In] IntPtr pInstance);

		/// <summary>Used to asynchronously return the results of an mDNS query.</summary>
		/// <param name="pQueryContext">A pointer to the user context that was passed to DnsServiceBrowse.</param>
		/// <param name="pQueryHandle">A pointer to the MDNS_QUERY_HANDLE structure that was passed to DnsStartMulticastQuery.</param>
		/// <param name="pQueryResults">
		/// A pointer to a DNS_QUERY_RESULT structure that contains the query results. Your application is responsible for freeing the
		/// contained in this structure using DnsRecordListFree.
		/// </param>
		/// <returns>None</returns>
		// https://docs.microsoft.com/en-us/windows/win32/api/windns/nc-windns-mdns_query_callback MDNS_QUERY_CALLBACK MdnsQueryCallback;
		// void MdnsQueryCallback( PVOID pQueryContext, PMDNS_QUERY_HANDLE pQueryHandle, PDNS_QUERY_RESULT pQueryResults ) {...}
		[PInvokeData("windns.h")]
		[UnmanagedFunctionPointer(CallingConvention.Winapi)]
		public delegate void MDNS_QUERY_CALLBACK(IntPtr pQueryContext, IntPtr pQueryHandle, IntPtr pQueryResults);

		/// <summary>Byte flip DNS header to\from host order.</summary>
		/// <param name="mBuf">The DNS_MESSAGE_BUFFER instance whose values are to be flipped.</param>
		[PInvokeData("windns.h")]
		public static void DNS_BYTE_FLIP_HEADER_COUNTS(ref DNS_MESSAGE_BUFFER mBuf)
		{
			INLINE_HTONS(ref mBuf.MessageHead.Xid);
			INLINE_HTONS(ref mBuf.MessageHead.QuestionCount);
			INLINE_HTONS(ref mBuf.MessageHead.AnswerCount);
			INLINE_HTONS(ref mBuf.MessageHead.NameServerCount);
			INLINE_HTONS(ref mBuf.MessageHead.AdditionalCount);

			static void INLINE_HTONS(ref ushort value) => value = (ushort)((value << 8) | (value >> 8));
		}

		/// <summary>
		/// <para>
		/// The <c>DnsAcquireContextHandle</c> function type acquires a context handle to a set of credentials. Like many DNS functions, the
		/// <c>DnsAcquireContextHandle</c> function type is implemented in multiple forms to facilitate different character encoding. Based
		/// on the character encoding involved, use one of the following functions:
		/// </para>
		/// <list type="bullet">
		/// <item>
		/// <term><c>DnsAcquireContextHandle_A</c> (_A for ANSI encoding)</term>
		/// </item>
		/// <item>
		/// <term><c>DnsAcquireContextHandle_W</c> (_W for Unicode encoding)</term>
		/// </item>
		/// </list>
		/// </summary>
		/// <param name="CredentialFlags">
		/// A flag that indicates the character encoding. Set to <c>TRUE</c> for Unicode, <c>FALSE</c> for ANSI.
		/// </param>
		/// <param name="Credentials">
		/// A pointer to a SEC_WINNT_AUTH_IDENTITY_W structure or a <c>SEC_WINNT_AUTH_IDENTITY_A</c> structure that contains the name,
		/// domain, and password of the account to be used in a secure dynamic update. If CredentialFlags is set to <c>TRUE</c>, Credentials
		/// points to a <c>SEC_WINNT_AUTH_IDENTITY_W</c> structure; otherwise, Credentials points to a <c>SEC_WINNT_AUTH_IDENTITY_A</c>
		/// structure. If not specified, the credentials of the calling service are used. This parameter is optional.
		/// </param>
		/// <param name="pContext">A pointer to a handle pointing to the returned credentials.</param>
		/// <returns>
		/// Returns success confirmation upon successful completion. Otherwise, returns the appropriate DNS-specific error code as defined
		/// in Winerror.h.
		/// </returns>
		// https://docs.microsoft.com/en-us/windows/win32/api/windns/nf-windns-dnsacquirecontexthandle_w DNS_STATUS
		// DnsAcquireContextHandle_W( DWORD CredentialFlags, PVOID Credentials, PHANDLE pContext );
		[DllImport(Lib.Dnsapi, SetLastError = false, EntryPoint = "DnsAcquireContextHandle_W", CharSet = CharSet.Unicode)]
		[PInvokeData("windns.h", MSDNShortId = "9a820165-2f78-44f4-b49f-dc7a2b6fb4e5")]
		public static extern DNS_STATUS DnsAcquireContextHandle([MarshalAs(UnmanagedType.Bool)] bool CredentialFlags, [In, Optional] IntPtr Credentials, out SafeHDNSCONTEXT pContext);

		/// <summary>The <c>DnsCancelQuery</c> function can be used to cancel a pending query to the DNS namespace.</summary>
		/// <param name="pCancelHandle">
		/// A pointer to a DNS_QUERY_CANCEL structure used to cancel an asynchronous DNS query. The structure must have been returned in the
		/// pCancelHandle parameter of a previous call to DnsQueryEx.
		/// </param>
		/// <returns>
		/// Returns success confirmation upon successful completion. Otherwise, it returns the appropriate DNS-specific error code as
		/// defined in Winerror.h.
		/// </returns>
		/// <remarks>
		/// <para>
		/// <c>DnsCancelQuery</c> does not wait for a query to complete before cancelling. Therefore, applications should track pending
		/// queries through their DNS_QUERY_COMPLETION_ROUTINE DNS callbacks.
		/// </para>
		/// <para>pCancelHandle is valid until the DNS_QUERY_COMPLETION_ROUTINE DNS callback is invoked and <c>DnsCancelQuery</c> completes.</para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/windns/nf-windns-dnscancelquery DNS_STATUS DnsCancelQuery( PDNS_QUERY_CANCEL
		// pCancelHandle );
		[DllImport(Lib.Dnsapi, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("windns.h", MSDNShortId = "E5F422AA-D4E6-4F9F-A57C-608CE9317658")]
		public static extern DNS_STATUS DnsCancelQuery(in DNS_QUERY_CANCEL pCancelHandle);

		/// <summary>
		/// The <c>DnsExtractRecordsFromMessage</c> function type extracts resource records (RR) from a DNS message, and stores those
		/// records in a DNS_RECORD structure. Like many DNS functions, the <c>DnsExtractRecordsFromMessage</c> function type is implemented
		/// in multiple forms to facilitate different character encoding.
		/// </summary>
		/// <param name="pDnsBuffer">A pointer to a DNS_MESSAGE_BUFFER structure that contains the DNS response message.</param>
		/// <param name="wMessageLength">The size, in bytes, of the message in pDnsBuffer.</param>
		/// <param name="ppRecord">
		/// A pointer to a DNS_RECORD structure that contains the list of extracted RRs. To free these records, use the DnsRecordListFree function.
		/// </param>
		/// <returns>
		/// Returns success confirmation upon successful completion. Otherwise, returns the appropriate DNS-specific error code as defined
		/// in Winerror.h.
		/// </returns>
		/// <remarks>
		/// The <c>DnsExtractRecordsFromMessage</c> function is designed to operate on messages in host byte order. As such, received
		/// messages should be converted from network byte order to host byte order before extraction, or before retransmission onto the
		/// network. Use the DNS_BYTE_FLIP_HEADER_COUNTS macro to change byte ordering.
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/windns/nf-windns-dnsextractrecordsfrommessage_w DNS_STATUS
		// DnsExtractRecordsFromMessage_W( PDNS_MESSAGE_BUFFER pDnsBuffer, WORD wMessageLength, PDNS_RECORD *ppRecord );
		[DllImport(Lib.Dnsapi, SetLastError = false, EntryPoint = "DnsExtractRecordsFromMessage_W", CharSet = CharSet.Unicode)]
		[PInvokeData("windns.h", MSDNShortId = "0179bf3e-9243-4dd7-a2ab-e2f6f4bf4b82")]
		public static extern DNS_STATUS DnsExtractRecordsFromMessage([In] IntPtr pDnsBuffer, ushort wMessageLength, out SafeDnsRecordList ppRecord);

		/// <summary>The <c>DnsFree</c> function frees memory allocated for DNS records that was obtained using the DnsQuery function.</summary>
		/// <param name="pData">A pointer to the DNS data to be freed.</param>
		/// <param name="FreeType">
		/// A value that specifies the type of DNS data in pData. For more information and a list of values, see the DNS_FREE_TYPE enumeration.
		/// </param>
		/// <returns>None</returns>
		// https://docs.microsoft.com/en-us/windows/win32/api/windns/nf-windns-dnsfree void DnsFree( _Frees_ptr_opt_ PVOID pData,
		// DNS_FREE_TYPE FreeType );
		[DllImport(Lib.Dnsapi, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("windns.h", MSDNShortId = "32baa672-2106-4c4a-972a-f7f79996b613")]
		public static extern void DnsFree(IntPtr pData, DNS_FREE_TYPE FreeType);

		/// <summary>
		/// The <c>DnsFreeProxyName</c> function frees memory allocated for the <c>proxyName</c> member of a DNS_PROXY_INFORMATION structure
		/// obtained using the DnsGetProxyInformation function.
		/// </summary>
		/// <param name="proxyName">A pointer to the <c>proxyName</c> string to be freed.</param>
		/// <returns>None</returns>
		// https://docs.microsoft.com/en-us/windows/win32/api/windns/nf-windns-dnsfreeproxyname void DnsFreeProxyName( _Frees_ptr_opt_ PWSTR
		// proxyName );
		[DllImport(Lib.Dnsapi, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("windns.h", MSDNShortId = "4c69d548-3bb5-4609-9fc5-3a829a285956")]
		public static extern void DnsFreeProxyName(IntPtr proxyName);

		/// <summary>Gets a list of cached domain names in the DNS client.</summary>
		/// <param name="ppCacheData">The cached data list.</param>
		/// <returns>
		/// Returns success confirmation upon successful completion. Otherwise, returns the appropriate DNS-specific error code as defined
		/// in Winerror.h.
		/// </returns>
		[DllImport(Lib.Dnsapi, SetLastError = true, ExactSpelling = true)]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool DnsGetCacheDataTable(out SafeDnsCacheDataTable ppCacheData);

		/// <summary>
		/// The <c>DnsGetProxyInformation</c> function returns the proxy information for a DNS server's name resolution policy table.
		/// </summary>
		/// <param name="hostName">A pointer to a string that represents the name of the DNS server whose proxy information is returned.</param>
		/// <param name="proxyInformation">A pointer to a DNS_PROXY_INFORMATION structure that contains the proxy information for hostName.</param>
		/// <param name="defaultProxyInformation">
		/// A pointer to a DNS_PROXY_INFORMATION structure that contains the default proxy information for hostName. This proxy information
		/// is for the wildcard DNS policy.
		/// </param>
		/// <param name="completionRoutine">Reserved. Do not use.</param>
		/// <param name="completionContext">Reserved. Do not use.</param>
		/// <returns>
		/// The <c>DnsGetProxyInformation</c> function returns the appropriate DNS-specific error code as defined in Winerror.h. The
		/// following are possible return values:
		/// </returns>
		// https://docs.microsoft.com/en-us/windows/win32/api/windns/nf-windns-dnsgetproxyinformation DWORD DnsGetProxyInformation( PCWSTR
		// hostName, DNS_PROXY_INFORMATION *proxyInformation, DNS_PROXY_INFORMATION *defaultProxyInformation, DNS_PROXY_COMPLETION_ROUTINE
		// completionRoutine, void *completionContext );
		[DllImport(Lib.Dnsapi, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("windns.h", MSDNShortId = "fdc8eb09-e071-4f03-974a-2b11a657ab18")]
		public static extern Win32Error DnsGetProxyInformation([MarshalAs(UnmanagedType.LPWStr)] string hostName, ref DNS_PROXY_INFORMATION proxyInformation, ref DNS_PROXY_INFORMATION defaultProxyInformation,
			IntPtr completionRoutine = default, IntPtr completionContext = default);

		/// <summary>
		/// The <c>DnsGetProxyInformation</c> function returns the proxy information for a DNS server's name resolution policy table.
		/// </summary>
		/// <param name="hostName">A pointer to a string that represents the name of the DNS server whose proxy information is returned.</param>
		/// <param name="proxyInformation">A pointer to a DNS_PROXY_INFORMATION structure that contains the proxy information for hostName.</param>
		/// <param name="defaultProxyInformation">
		/// A pointer to a DNS_PROXY_INFORMATION structure that contains the default proxy information for hostName. This proxy information
		/// is for the wildcard DNS policy.
		/// </param>
		/// <param name="completionRoutine">Reserved. Do not use.</param>
		/// <param name="completionContext">Reserved. Do not use.</param>
		/// <returns>
		/// The <c>DnsGetProxyInformation</c> function returns the appropriate DNS-specific error code as defined in Winerror.h. The
		/// following are possible return values:
		/// </returns>
		// https://docs.microsoft.com/en-us/windows/win32/api/windns/nf-windns-dnsgetproxyinformation DWORD DnsGetProxyInformation( PCWSTR
		// hostName, DNS_PROXY_INFORMATION *proxyInformation, DNS_PROXY_INFORMATION *defaultProxyInformation, DNS_PROXY_COMPLETION_ROUTINE
		// completionRoutine, void *completionContext );
		[DllImport(Lib.Dnsapi, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("windns.h", MSDNShortId = "fdc8eb09-e071-4f03-974a-2b11a657ab18")]
		public static extern Win32Error DnsGetProxyInformation([MarshalAs(UnmanagedType.LPWStr)] string hostName, ref DNS_PROXY_INFORMATION proxyInformation, IntPtr defaultProxyInformation = default,
			IntPtr completionRoutine = default, IntPtr completionContext = default);

		/// <summary>
		/// The <c>DnsModifyRecordsInSet</c> function adds, modifies or removes a Resource Record (RR) set that may have been previously
		/// registered with DNS servers.
		/// </summary>
		/// <param name="pAddRecords">A pointer to the DNS_RECORD structure that contains the RRs to be added to the RR set.</param>
		/// <param name="pDeleteRecords">A pointer to the DNS_RECORD structure that contains the RRs to be deleted from the RR set.</param>
		/// <param name="Options">
		/// A value that contains a bitmap of DNS Update Options. Options can be combined and all options override <c>DNS_UPDATE_SECURITY_USE_DEFAULT</c>.
		/// </param>
		/// <param name="hCredentials">
		/// A handle to the credentials of a specific account. Used when secure dynamic update is required. This parameter is optional.
		/// </param>
		/// <param name="pExtraList">This parameter is reserved for future use and must be set to <c>NULL</c>.</param>
		/// <param name="pReserved">This parameter is reserved for future use and must be set to <c>NULL</c>.</param>
		/// <returns>
		/// Returns success confirmation upon successful completion. Otherwise, it returns the appropriate DNS-specific error code as
		/// defined in Winerror.h.
		/// </returns>
		/// <remarks>
		/// <para>The <c>DnsModifyRecordsInSet</c> function type executes in the following steps.</para>
		/// <list type="number">
		/// <item>
		/// <term>
		/// Records specified in pDeleteRecords are deleted. If pDeleteRecords is empty or does not contain records that exist in the
		/// current set, the <c>DnsModifyRecordsInSet</c> function goes to the next step.
		/// </term>
		/// </item>
		/// <item>
		/// <term>Records specified in pAddRecords are added. If pAddRecords is empty, the operation completes without adding any records.</term>
		/// </item>
		/// </list>
		/// <para>
		/// To add a new record, provide no records in pDeleteRecords, and provide the record to be added in pAddRecords. To modify a
		/// record, specify the record being modified in pDeleteRecords, then add the modified version of that record by placing it in
		/// pAddRecords. To delete records, specify only records to be deleted. Multiple records can be added or deleted in a single call to
		/// <c>DnsModifyRecordsInSet</c>; however, the value of the <c>pName</c> member in each DNS_RECORD must be the same or the call will
		/// fail. If a record specified in pAddRecords is already present, no change occurs.
		/// </para>
		/// <para>If no server list is specified, the default name server is queried.</para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/windns/nf-windns-dnsmodifyrecordsinset_a DNS_STATUS DnsModifyRecordsInSet_A(
		// PDNS_RECORD pAddRecords, PDNS_RECORD pDeleteRecords, DWORD Options, HANDLE hCredentials, PVOID pExtraList, PVOID pReserved );
		[DllImport(Lib.Dnsapi, SetLastError = false, EntryPoint = "DnsModifyRecordsInSet_W", CharSet = CharSet.Unicode)]
		[PInvokeData("windns.h", MSDNShortId = "4287b4e1-a7a2-4b73-b5bb-21bc639bae73")]
		public static extern DNS_STATUS DnsModifyRecordsInSet(in DNS_RECORD pAddRecords, in DNS_RECORD pDeleteRecords, DNS_UPDATE Options, [Optional] IntPtr hCredentials, [In, Out, Optional] IntPtr pExtraList, IntPtr pReserved = default);

		/// <summary>
		/// The <c>DnsModifyRecordsInSet</c> function adds, modifies or removes a Resource Record (RR) set that may have been previously
		/// registered with DNS servers.
		/// </summary>
		/// <param name="pAddRecords">A pointer to the DNS_RECORD structure that contains the RRs to be added to the RR set.</param>
		/// <param name="pDeleteRecords">A pointer to the DNS_RECORD structure that contains the RRs to be deleted from the RR set.</param>
		/// <param name="Options">
		/// A value that contains a bitmap of DNS Update Options. Options can be combined and all options override <c>DNS_UPDATE_SECURITY_USE_DEFAULT</c>.
		/// </param>
		/// <param name="hCredentials">
		/// A handle to the credentials of a specific account. Used when secure dynamic update is required. This parameter is optional.
		/// </param>
		/// <param name="pExtraList">This parameter is reserved for future use and must be set to <c>NULL</c>.</param>
		/// <param name="pReserved">This parameter is reserved for future use and must be set to <c>NULL</c>.</param>
		/// <returns>
		/// Returns success confirmation upon successful completion. Otherwise, it returns the appropriate DNS-specific error code as
		/// defined in Winerror.h.
		/// </returns>
		/// <remarks>
		/// <para>The <c>DnsModifyRecordsInSet</c> function type executes in the following steps.</para>
		/// <list type="number">
		/// <item>
		/// <term>
		/// Records specified in pDeleteRecords are deleted. If pDeleteRecords is empty or does not contain records that exist in the
		/// current set, the <c>DnsModifyRecordsInSet</c> function goes to the next step.
		/// </term>
		/// </item>
		/// <item>
		/// <term>Records specified in pAddRecords are added. If pAddRecords is empty, the operation completes without adding any records.</term>
		/// </item>
		/// </list>
		/// <para>
		/// To add a new record, provide no records in pDeleteRecords, and provide the record to be added in pAddRecords. To modify a
		/// record, specify the record being modified in pDeleteRecords, then add the modified version of that record by placing it in
		/// pAddRecords. To delete records, specify only records to be deleted. Multiple records can be added or deleted in a single call to
		/// <c>DnsModifyRecordsInSet</c>; however, the value of the <c>pName</c> member in each DNS_RECORD must be the same or the call will
		/// fail. If a record specified in pAddRecords is already present, no change occurs.
		/// </para>
		/// <para>If no server list is specified, the default name server is queried.</para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/windns/nf-windns-dnsmodifyrecordsinset_a DNS_STATUS DnsModifyRecordsInSet_A(
		// PDNS_RECORD pAddRecords, PDNS_RECORD pDeleteRecords, DWORD Options, HANDLE hCredentials, PVOID pExtraList, PVOID pReserved );
		[DllImport(Lib.Dnsapi, SetLastError = false, EntryPoint = "DnsModifyRecordsInSet_W", CharSet = CharSet.Unicode)]
		[PInvokeData("windns.h", MSDNShortId = "4287b4e1-a7a2-4b73-b5bb-21bc639bae73")]
		public static extern DNS_STATUS DnsModifyRecordsInSet([In] IntPtr pAddRecords, [In] IntPtr pDeleteRecords, DNS_UPDATE Options, [Optional] IntPtr hCredentials, [In, Out, Optional] IntPtr pExtraList, IntPtr pReserved = default);

		/// <summary>The <c>DnsNameCompare</c> function compares two DNS names.</summary>
		/// <param name="pName1"/>
		/// <param name="pName2"/>
		/// <returns>Returns <c>TRUE</c> if the compared names are equivalent, <c>FALSE</c> if they are not.</returns>
		/// <remarks>
		/// <para>Name comparisons are not case sensitive, and trailing dots are ignored.</para>
		/// <para>
		/// As with other DNS comparison functions, the <c>DnsNameCompare</c> function deems different encoding as an immediate indication
		/// of differing values, and as such, the same names with different characters encoding will not be reported identically.
		/// </para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/windns/nf-windns-dnsnamecompare_w BOOL DnsNameCompare_W( PCWSTR pName1, PCWSTR
		// pName2 );
		[DllImport(Lib.Dnsapi, SetLastError = false, EntryPoint = "DnsNameCompare_W", CharSet = CharSet.Unicode)]
		[PInvokeData("windns.h", MSDNShortId = "4a1512b3-8273-4632-9426-daa36456bce3")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool DnsNameCompare(string pName1, string pName2);

		/// <summary>
		/// <para>
		/// The <c>DnsQuery</c> function type is the generic query interface to the DNS namespace, and provides application developers with
		/// a DNS query resolution interface.
		/// </para>
		/// <para>Windows 8: The DnsQueryEx function should be used if an application requires asynchronous querries to the DNS namespace.</para>
		/// </summary>
		/// <param name="pszName">A pointer to a string that represents the DNS name to query.</param>
		/// <param name="wType">
		/// A value that represents the Resource Record (RR)DNS Record Type that is queried. <c>wType</c> determines the format of data
		/// pointed to by <c>ppQueryResultsSet</c>. For example, if the value of <c>wType</c> is <c>DNS_TYPE_A</c>, the format of data
		/// pointed to by <c>ppQueryResultsSet</c> is DNS_A_DATA.
		/// </param>
		/// <param name="Options">
		/// A value that contains a bitmap of DNS Query Options to use in the DNS query. Options can be combined and all options override <c>DNS_QUERY_STANDARD</c>.
		/// </param>
		/// <param name="pExtra">This parameter is reserved for future use and must be set to <c>NULL</c>.</param>
		/// <param name="ppQueryResults">
		/// Optional. A pointer to a pointer that points to the list of RRs that comprise the response. For more information, see the
		/// Remarks section.
		/// </param>
		/// <param name="pReserved">This parameter is reserved for future use and must be set to <c>NULL</c>.</param>
		/// <returns>
		/// Returns success confirmation upon successful completion. Otherwise, returns the appropriate DNS-specific error code as defined
		/// in Winerror.h.
		/// </returns>
		/// <remarks>
		/// <para>
		/// Applications that call the <c>DnsQuery</c> function build a query using a fully qualified DNS name and Resource Record (RR)
		/// type, and set query options depending on the type of service desired. When the <c>DNS_QUERY_STANDARD</c> option is set, DNS uses
		/// the resolver cache, queries first with UDP, then retries with TCP if the response is truncated, and requests that the server to
		/// perform recursive resolution on behalf of the client to resolve the query.
		/// </para>
		/// <para>Applications must free returned RR sets with the DnsRecordListFree function.</para>
		/// <para>
		/// <c>Note</c> When calling one of the <c>DnsQuery</c> function types, be aware that a DNS server may return multiple records in
		/// response to a query. A computer that is multihomed, for example, will receive multiple A records for the same IP address. The
		/// caller must use as many of the returned records as necessary.
		/// </para>
		/// <para>
		/// Consider the following scenario, in which multiple returned records require additional activity on behalf of the application: A
		/// <c>DnsQuery_A</c> function call is made for a multihomed computer and the application finds that the address associated with the
		/// first A record is not responding. The application should then attempt to use other IP addresses specified in the (additional) A
		/// records returned from the <c>DnsQuery_A</c> function call.
		/// </para>
		/// <para>If the lpstrName parameter is set to <c>NULL</c>, the <c>DnsQuery</c> function fails with the error <c>INVALID_PARAMETER</c>.</para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/windns/nf-windns-dnsquery_a DNS_STATUS DnsQuery_A( PCSTR pszName, WORD wType,
		// DWORD Options, PVOID pExtra, PDNS_RECORD *ppQueryResults, PVOID *pReserved );
		[DllImport(Lib.Dnsapi, SetLastError = false, EntryPoint = "DnsQuery_W", CharSet = CharSet.Unicode)]
		[PInvokeData("windns.h", MSDNShortId = "3d810b76-cea1-4904-9b5a-c2566b332c2c")]
		public static extern DNS_STATUS DnsQuery(string pszName, DNS_TYPE wType, DNS_QUERY_OPTIONS Options, [In, Out, Optional] IntPtr pExtra,
			out SafeDnsRecordList ppQueryResults, IntPtr pReserved = default);

		/// <summary>
		/// <para>
		/// The <c>DnsQuery</c> function type is the generic query interface to the DNS namespace, and provides application developers with
		/// a DNS query resolution interface.
		/// </para>
		/// <para>Windows 8: The DnsQueryEx function should be used if an application requires asynchronous querries to the DNS namespace.</para>
		/// </summary>
		/// <param name="pszName">A pointer to a string that represents the DNS name to query.</param>
		/// <param name="wType">
		/// A value that represents the Resource Record (RR)DNS Record Type that is queried. <c>wType</c> determines the format of data
		/// pointed to by <c>ppQueryResultsSet</c>. For example, if the value of <c>wType</c> is <c>DNS_TYPE_A</c>, the format of data
		/// pointed to by <c>ppQueryResultsSet</c> is DNS_A_DATA.
		/// </param>
		/// <param name="Options">
		/// A value that contains a bitmap of DNS Query Options to use in the DNS query. Options can be combined and all options override <c>DNS_QUERY_STANDARD</c>.
		/// </param>
		/// <param name="pExtra">This parameter is reserved for future use and must be set to <c>NULL</c>.</param>
		/// <param name="ppQueryResults">
		/// Optional. A pointer to a pointer that points to the list of RRs that comprise the response. For more information, see the
		/// Remarks section.
		/// </param>
		/// <param name="pReserved">This parameter is reserved for future use and must be set to <c>NULL</c>.</param>
		/// <returns>
		/// Returns success confirmation upon successful completion. Otherwise, returns the appropriate DNS-specific error code as defined
		/// in Winerror.h.
		/// </returns>
		/// <remarks>
		/// <para>
		/// Applications that call the <c>DnsQuery</c> function build a query using a fully qualified DNS name and Resource Record (RR)
		/// type, and set query options depending on the type of service desired. When the <c>DNS_QUERY_STANDARD</c> option is set, DNS uses
		/// the resolver cache, queries first with UDP, then retries with TCP if the response is truncated, and requests that the server to
		/// perform recursive resolution on behalf of the client to resolve the query.
		/// </para>
		/// <para>Applications must free returned RR sets with the DnsRecordListFree function.</para>
		/// <para>
		/// <c>Note</c> When calling one of the <c>DnsQuery</c> function types, be aware that a DNS server may return multiple records in
		/// response to a query. A computer that is multihomed, for example, will receive multiple A records for the same IP address. The
		/// caller must use as many of the returned records as necessary.
		/// </para>
		/// <para>
		/// Consider the following scenario, in which multiple returned records require additional activity on behalf of the application: A
		/// <c>DnsQuery_A</c> function call is made for a multihomed computer and the application finds that the address associated with the
		/// first A record is not responding. The application should then attempt to use other IP addresses specified in the (additional) A
		/// records returned from the <c>DnsQuery_A</c> function call.
		/// </para>
		/// <para>If the lpstrName parameter is set to <c>NULL</c>, the <c>DnsQuery</c> function fails with the error <c>INVALID_PARAMETER</c>.</para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/windns/nf-windns-dnsquery_a DNS_STATUS DnsQuery_A( PCSTR pszName, WORD wType,
		// DWORD Options, PVOID pExtra, PDNS_RECORD *ppQueryResults, PVOID *pReserved );
		[DllImport(Lib.Dnsapi, SetLastError = false, EntryPoint = "DnsQuery_W", CharSet = CharSet.Unicode)]
		[PInvokeData("windns.h", MSDNShortId = "3d810b76-cea1-4904-9b5a-c2566b332c2c")]
		public static extern DNS_STATUS DnsQuery(string pszName, DNS_TYPE wType, DNS_QUERY_OPTIONS Options, [In, Out, Optional] IntPtr pExtra,
			IntPtr ppQueryResults = default, IntPtr pReserved = default);

		/// <summary>
		/// The <c>DnsQueryConfig</c> function enables application programmers to query for the configuration of the local computer or a
		/// specific adapter.
		/// </summary>
		/// <param name="Config">A DNS_CONFIG_TYPE value that specifies the configuration type of the information to be queried.</param>
		/// <param name="Flag">
		/// <para>
		/// A value that specifies whether to allocate memory for the configuration information. Set Flag to <c>DNS_CONFIG_FLAG_ALLOC</c> to
		/// allocate memory; otherwise, set it to 0.
		/// </para>
		/// <para><c>Note</c> Free the allocated memory with LocalFree.</para>
		/// </param>
		/// <param name="pwsAdapterName">A pointer to a string that represents the adapter name against which the query is run.</param>
		/// <param name="pReserved">Reserved for future use.</param>
		/// <param name="pBuffer">
		/// <para>
		/// A pointer to a buffer that receives the query response. The following table shows the data type of the buffer for each of the
		/// Config parameter values.
		/// </para>
		/// <list type="table">
		/// <listheader>
		/// <term>Config parameter</term>
		/// <term>Data type of buffer</term>
		/// </listheader>
		/// <item>
		/// <term>DnsConfigPrimaryDomainName_W</term>
		/// <term>PWCHAR</term>
		/// </item>
		/// <item>
		/// <term>DnsConfigPrimaryDomainName_A</term>
		/// <term>PCHAR</term>
		/// </item>
		/// <item>
		/// <term>DnsConfigPrimaryDomainName_UTF8</term>
		/// <term>PCHAR</term>
		/// </item>
		/// <item>
		/// <term>DnsConfigAdapterDomainName_W</term>
		/// <term>Not implemented</term>
		/// </item>
		/// <item>
		/// <term>DnsConfigAdapterDomainName_A</term>
		/// <term>Not implemented</term>
		/// </item>
		/// <item>
		/// <term>DnsConfigAdapterDomainName_UTF8</term>
		/// <term>Not implemented</term>
		/// </item>
		/// <item>
		/// <term>DnsConfigDnsServerList</term>
		/// <term>IP4_ARRAY</term>
		/// </item>
		/// <item>
		/// <term>DnsConfigSearchList</term>
		/// <term>Not implemented</term>
		/// </item>
		/// <item>
		/// <term>DnsConfigAdapterInfo</term>
		/// <term>Not implemented</term>
		/// </item>
		/// <item>
		/// <term>DnsConfigPrimaryHostNameRegistrationEnabled</term>
		/// <term>DWORD</term>
		/// </item>
		/// <item>
		/// <term>DnsConfigAdapterHostNameRegistrationEnabled</term>
		/// <term>DWORD</term>
		/// </item>
		/// <item>
		/// <term>DnsConfigAddressRegistrationMaxCount</term>
		/// <term>DWORD</term>
		/// </item>
		/// <item>
		/// <term>DnsConfigHostName_W</term>
		/// <term>PWCHAR</term>
		/// </item>
		/// <item>
		/// <term>DnsConfigHostName_A</term>
		/// <term>PCHAR</term>
		/// </item>
		/// <item>
		/// <term>DnsConfigHostName_UTF8</term>
		/// <term>PCHAR</term>
		/// </item>
		/// <item>
		/// <term>DnsConfigFullHostName_W</term>
		/// <term>PWCHAR</term>
		/// </item>
		/// <item>
		/// <term>DnsConfigFullHostName_A</term>
		/// <term>PCHAR</term>
		/// </item>
		/// <item>
		/// <term>DnsConfigFullHostName_UTF8</term>
		/// <term>PCHAR</term>
		/// </item>
		/// </list>
		/// </param>
		/// <param name="pBufLen">
		/// The length of the buffer, in bytes. If the buffer provided is not sufficient, an error is returned and pBufferLength contains
		/// the minimum necessary buffer size. Ignored on input if Flag is set to <c>TRUE</c>.
		/// </param>
		/// <returns>
		/// Returns success confirmation upon successful completion. Otherwise, returns the appropriate DNS-specific error code as defined
		/// in Winerror.h.
		/// </returns>
		// https://docs.microsoft.com/en-us/windows/win32/api/windns/nf-windns-dnsqueryconfig DNS_STATUS DnsQueryConfig( DNS_CONFIG_TYPE
		// Config, DWORD Flag, PCWSTR pwsAdapterName, PVOID pReserved, PVOID pBuffer, PDWORD pBufLen );
		[DllImport(Lib.Dnsapi, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("windns.h", MSDNShortId = "83de7df8-7e89-42fe-b609-1dc173afc9df")]
		public static extern DNS_STATUS DnsQueryConfig(DNS_CONFIG_TYPE Config, DNS_CONFIG_FLAG Flag, [Optional, MarshalAs(UnmanagedType.LPWStr)] string pwsAdapterName,
			[In, Optional] IntPtr pReserved, IntPtr pBuffer, ref uint pBufLen);

		/// <summary>
		/// <para>
		/// The <c>DnsQueryEx</c> function is the asynchronous generic query interface to the DNS namespace, and provides application
		/// developers with a DNS query resolution interface.
		/// </para>
		/// <para>Like DnsQuery, <c>DnsQueryEx</c> can be used to make synchronous queries to the DNS namespace as well.</para>
		/// </summary>
		/// <param name="pQueryRequest">
		/// <para>A pointer to a DNS_QUERY_REQUEST structure that contains the query request information.</para>
		/// <para>
		/// <c>Note</c> By omitting the DNS_QUERY_COMPLETION_ROUTINE callback from the <c>pQueryCompleteCallback</c> member of this
		/// structure, <c>DnsQueryEx</c> is called synchronously.
		/// </para>
		/// </param>
		/// <param name="pQueryResults">
		/// <para>
		/// A pointer to a DNS_QUERY_RESULT structure that contains the results of the query. On input, the <c>version</c> member of
		/// pQueryResults must be <c>DNS_QUERY_REQUEST_VERSION1</c> and all other members should be <c>NULL</c>. On output, the remaining
		/// members will be filled as part of the query complete.
		/// </para>
		/// <para>
		/// <c>Note</c> For asynchronous queries, an application should not free this structure until the DNS_QUERY_COMPLETION_ROUTINE
		/// callback is invoked. When the query completes, the DNS_QUERY_RESULT structure contains a pointer to a list of DNS_RECORDS that
		/// should be freed using DnsRecordListFree.
		/// </para>
		/// </param>
		/// <param name="pCancelHandle">
		/// <para>A pointer to a DNS_QUERY_CANCEL structure that can be used to cancel a pending asynchronous query.</para>
		/// <para><c>Note</c> An application should not free this structure until the DNS_QUERY_COMPLETION_ROUTINE callback is invoked.</para>
		/// </param>
		/// <returns>
		/// <para>The <c>DnsQueryEx</c> function has the following possible return values:</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Return code</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>ERROR_SUCCESS</term>
		/// <term>The call was successful.</term>
		/// </item>
		/// <item>
		/// <term>ERROR_INVALID_PARAMETER</term>
		/// <term>Either the pQueryRequest or pQueryRequest parameters are uninitialized or contain the wrong version.</term>
		/// </item>
		/// <item>
		/// <term>DNS RCODE</term>
		/// <term>The call resulted in an RCODE error.</term>
		/// </item>
		/// <item>
		/// <term>DNS_INFO_NO_RECORDS</term>
		/// <term>No records in the response.</term>
		/// </item>
		/// <item>
		/// <term>DNS_REQUEST_PENDING</term>
		/// <term>The query will be completed asynchronously.</term>
		/// </item>
		/// </list>
		/// </returns>
		/// <remarks>
		/// <para>
		/// If a call to <c>DnsQueryEx</c> completes synchronously (i.e., the function return value is not <c>DNS_REQUEST_PENDING</c>), the
		/// <c>pQueryRecords</c> member of pQueryResults contains a pointer to a list of DNS_RECORDS and <c>DnsQueryEx</c> will return
		/// either error or success.
		/// </para>
		/// <para>The following conditions invoke a synchronous call to <c>DnsQueryEx</c> and do not utilize the DNS callback:</para>
		/// <list type="bullet">
		/// <item>
		/// <term>The DNS_QUERY_COMPLETION_ROUTINE callback is omitted from the <c>pQueryCompleteCallback</c> member of pQueryRequest.</term>
		/// </item>
		/// <item>
		/// <term>A query is for the local machine name and A or AAAA type Resource Records (RR).</term>
		/// </item>
		/// <item>
		/// <term>A call to <c>DnsQueryEx</c> queries an IPv4 or IPv6 address.</term>
		/// </item>
		/// <item>
		/// <term>A call to <c>DnsQueryEx</c> returns in error.</term>
		/// </item>
		/// </list>
		/// <para>
		/// If a call to <c>DnsQueryEx</c> completes asynchronously, the results of the query are returned by the
		/// DNS_QUERY_COMPLETION_ROUTINE callback in pQueryRequest, the <c>QueryStatus</c> member of pQueryResults contains
		/// <c>DNS_REQUEST_PENDING</c>, and <c>DnsQueryEx</c> returns <c>DNS_REQUEST_PENDING</c>. Applications should track the
		/// pQueryResults structure that is passed into <c>DnsQueryEx</c> until the DNS callback succeeds. Applications can cancel an
		/// asynchronous query using the pCancelHandle handle returned by <c>DnsQueryEx</c>.
		/// </para>
		/// <para>
		/// pCancelHandle returned from an asynchronous call to <c>DnsQueryEx</c> and pQueryContext is valid until the
		/// DNS_QUERY_COMPLETION_ROUTINE DNS callback is invoked.
		/// </para>
		/// <para>
		/// <c>Note</c> Applications are notified of asynchronous <c>DnsQueryEx</c> completion through the DNS_QUERY_COMPLETION_ROUTINE
		/// callback within the same process context.
		/// </para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/windns/nf-windns-dnsqueryex DNS_STATUS DnsQueryEx( PDNS_QUERY_REQUEST
		// pQueryRequest, PDNS_QUERY_RESULT pQueryResults, PDNS_QUERY_CANCEL pCancelHandle );
		[DllImport(Lib.Dnsapi, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("windns.h", MSDNShortId = "22664B9A-5010-42E7-880B-8D5B16A9F2DC")]
		public static extern DNS_STATUS DnsQueryEx(in DNS_QUERY_REQUEST pQueryRequest, ref DNS_QUERY_RESULT pQueryResults, out DNS_QUERY_CANCEL pCancelHandle);

		/// <summary>The <c>DnsRecordCompare</c> function compares two DNS resource records (RR).</summary>
		/// <param name="pRecord1">A pointer to a DNS_RECORD structure that contains the first DNS RR of the comparison pair.</param>
		/// <param name="pRecord2">A pointer to a DNS_RECORD structure that contains the second DNS RR of the comparison pair.</param>
		/// <returns>Returns <c>TRUE</c> if the compared records are equivalent, <c>FALSE</c> if they are not.</returns>
		/// <remarks>
		/// When comparing records, DNS RRs that are stored using different character encoding are treated by the <c>DnsRecordCompare</c>
		/// function as different, even if the records are otherwise equivalent.
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/windns/nf-windns-dnsrecordcompare BOOL DnsRecordCompare( PDNS_RECORD pRecord1,
		// PDNS_RECORD pRecord2 );
		[DllImport(Lib.Dnsapi, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("windns.h", MSDNShortId = "c4449a23-d6d3-4f27-a963-a84144983e5e")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool DnsRecordCompare(in DNS_RECORD pRecord1, in DNS_RECORD pRecord2);

		/// <summary>The <c>DnsRecordCompare</c> function compares two DNS resource records (RR).</summary>
		/// <param name="pRecord1">A pointer to a DNS_RECORD structure that contains the first DNS RR of the comparison pair.</param>
		/// <param name="pRecord2">A pointer to a DNS_RECORD structure that contains the second DNS RR of the comparison pair.</param>
		/// <returns>Returns <c>TRUE</c> if the compared records are equivalent, <c>FALSE</c> if they are not.</returns>
		/// <remarks>
		/// When comparing records, DNS RRs that are stored using different character encoding are treated by the <c>DnsRecordCompare</c>
		/// function as different, even if the records are otherwise equivalent.
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/windns/nf-windns-dnsrecordcompare BOOL DnsRecordCompare( PDNS_RECORD pRecord1,
		// PDNS_RECORD pRecord2 );
		[DllImport(Lib.Dnsapi, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("windns.h", MSDNShortId = "c4449a23-d6d3-4f27-a963-a84144983e5e")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool DnsRecordCompare([In] IntPtr pRecord1, [In] IntPtr pRecord2);

		/// <summary>
		/// The <c>DnsRecordCopyEx</c> function creates a copy of a specified resource record (RR). The <c>DnsRecordCopyEx</c> function is
		/// also capable of converting the character encoding during the copy operation.
		/// </summary>
		/// <param name="pRecord">A pointer to a DNS_RECORD structure that contains the RR to be copied.</param>
		/// <param name="CharSetIn">A DNS_CHARSET value that specifies the character encoding of the source RR.</param>
		/// <param name="CharSetOut">A DNS_CHARSET value that specifies the character encoding required of the destination record.</param>
		/// <returns>Successful execution returns a pointer to the (newly created) destination record. Otherwise, returns null.</returns>
		/// <remarks>The CharSetIn parameter is used only if the character encoding of the source RR is not specified in pRecord.</remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/windns/nf-windns-dnsrecordcopyex PDNS_RECORD DnsRecordCopyEx( PDNS_RECORD
		// pRecord, DNS_CHARSET CharSetIn, DNS_CHARSET CharSetOut );
		[DllImport(Lib.Dnsapi, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("windns.h", MSDNShortId = "b5a74799-75fc-4489-9efa-c15b2def2ae7")]
		public static extern IntPtr DnsRecordCopyEx(in DNS_RECORD pRecord, DNS_CHARSET CharSetIn, DNS_CHARSET CharSetOut);

		/// <summary>
		/// The <c>DnsRecordCopyEx</c> function creates a copy of a specified resource record (RR). The <c>DnsRecordCopyEx</c> function is
		/// also capable of converting the character encoding during the copy operation.
		/// </summary>
		/// <param name="pRecord">A pointer to a DNS_RECORD structure that contains the RR to be copied.</param>
		/// <param name="CharSetIn">A DNS_CHARSET value that specifies the character encoding of the source RR.</param>
		/// <param name="CharSetOut">A DNS_CHARSET value that specifies the character encoding required of the destination record.</param>
		/// <returns>Successful execution returns a pointer to the (newly created) destination record. Otherwise, returns null.</returns>
		/// <remarks>The CharSetIn parameter is used only if the character encoding of the source RR is not specified in pRecord.</remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/windns/nf-windns-dnsrecordcopyex PDNS_RECORD DnsRecordCopyEx( PDNS_RECORD
		// pRecord, DNS_CHARSET CharSetIn, DNS_CHARSET CharSetOut );
		[DllImport(Lib.Dnsapi, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("windns.h", MSDNShortId = "b5a74799-75fc-4489-9efa-c15b2def2ae7")]
		public static extern IntPtr DnsRecordCopyEx([In] IntPtr pRecord, DNS_CHARSET CharSetIn, DNS_CHARSET CharSetOut);

		/// <summary>The <c>DnsRecordListFree</c> function frees memory allocated for DNS records obtained using the DnsQuery function.</summary>
		/// <param name="p">A pointer to a DNS_RECORD structure that contains the list of DNS records to be freed.</param>
		/// <param name="t">
		/// A specifier of how the record list should be freed. The only type currently supported is a deep freeing of the entire record
		/// list. For more information and a list of values, see the DNS_FREE_TYPE enumeration.
		/// </param>
		/// <returns>None</returns>
		/// <remarks>
		/// The <c>DnsRecordListFree</c> function can be used to free memory allocated from query results obtained using a DnsQuery function
		/// call; it cannot free memory allocated for DNS record lists created manually.
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/windns/nf-windns-dnsrecordlistfree void DnsRecordListFree( p, t );
		[PInvokeData("windns.h", MSDNShortId = "fc4c0cb4-646f-4946-8f07-b5a858f7064a")]
		public static void DnsRecordListFree(IntPtr p, DNS_FREE_TYPE t = DNS_FREE_TYPE.DnsFreeRecordList) => DnsFree(p, t);

		/// <summary>The <c>DnsRecordSetCompare</c> function compares two RR sets.</summary>
		/// <param name="pRR1">A pointer to a DNS_RECORD structure that contains the first DNS RR set of the comparison pair.</param>
		/// <param name="pRR2">A pointer to a DNS_RECORD structure that contains the second DNS resource record set of the comparison pair.</param>
		/// <param name="ppDiff1">
		/// A pointer to a DNS_RECORD pointer that contains the list of resource records built as a result of the arithmetic performed on
		/// them: <c>pRRSet1</c> minus <c>pRRSet2</c>.
		/// </param>
		/// <param name="ppDiff2">
		/// A pointer to a DNS_RECORD pointer that contains the list of resource records built as a result of the arithmetic performed on
		/// them: <c>pRRSet2</c> minus <c>pRRSet1</c>.
		/// </param>
		/// <returns>Returns <c>TRUE</c> if the compared record sets are equivalent, <c>FALSE</c> if they are not.</returns>
		/// <remarks>
		/// When comparing record sets, DNS resource records that are stored using different character encoding are treated by the
		/// <c>DnsRecordSetCompare</c> function as equivalent. Contrast this to the DnsRecordCompare function, in which equivalent records
		/// with different encoding are not returned as equivalent records.
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/windns/nf-windns-dnsrecordsetcompare BOOL DnsRecordSetCompare( PDNS_RECORD
		// pRR1, PDNS_RECORD pRR2, PDNS_RECORD *ppDiff1, PDNS_RECORD *ppDiff2 );
		[DllImport(Lib.Dnsapi, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("windns.h", MSDNShortId = "008cf2ba-ccb2-430a-85d9-68d424b6938f")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool DnsRecordSetCompare(in DNS_RECORD pRR1, in DNS_RECORD pRR2, out IntPtr ppDiff1, out IntPtr ppDiff2);

		/// <summary>The <c>DnsRecordSetCompare</c> function compares two RR sets.</summary>
		/// <param name="pRR1">A pointer to a DNS_RECORD structure that contains the first DNS RR set of the comparison pair.</param>
		/// <param name="pRR2">A pointer to a DNS_RECORD structure that contains the second DNS resource record set of the comparison pair.</param>
		/// <param name="ppDiff1">
		/// A pointer to a DNS_RECORD pointer that contains the list of resource records built as a result of the arithmetic performed on
		/// them: <c>pRRSet1</c> minus <c>pRRSet2</c>.
		/// </param>
		/// <param name="ppDiff2">
		/// A pointer to a DNS_RECORD pointer that contains the list of resource records built as a result of the arithmetic performed on
		/// them: <c>pRRSet2</c> minus <c>pRRSet1</c>.
		/// </param>
		/// <returns>Returns <c>TRUE</c> if the compared record sets are equivalent, <c>FALSE</c> if they are not.</returns>
		/// <remarks>
		/// When comparing record sets, DNS resource records that are stored using different character encoding are treated by the
		/// <c>DnsRecordSetCompare</c> function as equivalent. Contrast this to the DnsRecordCompare function, in which equivalent records
		/// with different encoding are not returned as equivalent records.
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/windns/nf-windns-dnsrecordsetcompare BOOL DnsRecordSetCompare( PDNS_RECORD
		// pRR1, PDNS_RECORD pRR2, PDNS_RECORD *ppDiff1, PDNS_RECORD *ppDiff2 );
		[DllImport(Lib.Dnsapi, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("windns.h", MSDNShortId = "008cf2ba-ccb2-430a-85d9-68d424b6938f")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool DnsRecordSetCompare([In] IntPtr pRR1, [In] IntPtr pRR2, out IntPtr ppDiff1, out IntPtr ppDiff2);

		/// <summary>
		/// The <c>DnsRecordSetCopyEx</c> function creates a copy of a specified resource record set. The <c>DnsRecordSetCopyEx</c> function
		/// is also capable of converting the character encoding during the copy operation.
		/// </summary>
		/// <param name="pRecordSet">A pointer to a DNS_RECORD structure that contains the resource record set to be copied.</param>
		/// <param name="CharSetIn">A DNS_CHARSET value that specifies the character encoding of the source resource record set.</param>
		/// <param name="CharSetOut">A DNS_CHARSET value that specifies the character encoding required of the destination record set.</param>
		/// <returns>Successful execution returns a pointer to the newly created destination record set. Otherwise, it returns null.</returns>
		/// <remarks>
		/// The CharSetIn parameter is used only if the character encoding of the source resource record set is not specified in pRecordSet.
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/windns/nf-windns-dnsrecordsetcopyex PDNS_RECORD DnsRecordSetCopyEx(
		// PDNS_RECORD pRecordSet, DNS_CHARSET CharSetIn, DNS_CHARSET CharSetOut );
		[DllImport(Lib.Dnsapi, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("windns.h", MSDNShortId = "bdf9d6b4-b9d7-4886-8ea6-1e1f4dbcc99a")]
		public static extern IntPtr DnsRecordSetCopyEx(in DNS_RECORD pRecordSet, DNS_CHARSET CharSetIn, DNS_CHARSET CharSetOut);

		/// <summary>
		/// The <c>DnsRecordSetCopyEx</c> function creates a copy of a specified resource record set. The <c>DnsRecordSetCopyEx</c> function
		/// is also capable of converting the character encoding during the copy operation.
		/// </summary>
		/// <param name="pRecordSet">A pointer to a DNS_RECORD structure that contains the resource record set to be copied.</param>
		/// <param name="CharSetIn">A DNS_CHARSET value that specifies the character encoding of the source resource record set.</param>
		/// <param name="CharSetOut">A DNS_CHARSET value that specifies the character encoding required of the destination record set.</param>
		/// <returns>Successful execution returns a pointer to the newly created destination record set. Otherwise, it returns null.</returns>
		/// <remarks>
		/// The CharSetIn parameter is used only if the character encoding of the source resource record set is not specified in pRecordSet.
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/windns/nf-windns-dnsrecordsetcopyex PDNS_RECORD DnsRecordSetCopyEx(
		// PDNS_RECORD pRecordSet, DNS_CHARSET CharSetIn, DNS_CHARSET CharSetOut );
		[DllImport(Lib.Dnsapi, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("windns.h", MSDNShortId = "bdf9d6b4-b9d7-4886-8ea6-1e1f4dbcc99a")]
		public static extern IntPtr DnsRecordSetCopyEx([In] IntPtr pRecordSet, DNS_CHARSET CharSetIn, DNS_CHARSET CharSetOut);

		/// <summary>The <c>DnsRecordSetDetach</c> function detaches the first record set from a specified list of DNS records.</summary>
		/// <param name="pRecordList">
		/// A pointer, on input, to a DNS_RECORD structure that contains the list prior to the detachment of the first DNS record in the
		/// list of DNS records. A pointer, on output to a <c>DNS_RECORD</c> structure that contains the list subsequent to the detachment
		/// of the DNS record.
		/// </param>
		/// <returns>On return, the <c>DnsRecordSetDetach</c> function points to the detached DNS record set.</returns>
		// https://docs.microsoft.com/en-us/windows/win32/api/windns/nf-windns-dnsrecordsetdetach PDNS_RECORD DnsRecordSetDetach(
		// PDNS_RECORD pRecordList );
		[DllImport(Lib.Dnsapi, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("windns.h", MSDNShortId = "434dc11f-19a9-434f-a024-9cdbb560f24c")]
		public static extern IntPtr DnsRecordSetDetach(in DNS_RECORD pRecordList);

		/// <summary>The <c>DnsRecordSetDetach</c> function detaches the first record set from a specified list of DNS records.</summary>
		/// <param name="pRecordList">
		/// A pointer, on input, to a DNS_RECORD structure that contains the list prior to the detachment of the first DNS record in the
		/// list of DNS records. A pointer, on output to a <c>DNS_RECORD</c> structure that contains the list subsequent to the detachment
		/// of the DNS record.
		/// </param>
		/// <returns>On return, the <c>DnsRecordSetDetach</c> function points to the detached DNS record set.</returns>
		// https://docs.microsoft.com/en-us/windows/win32/api/windns/nf-windns-dnsrecordsetdetach PDNS_RECORD DnsRecordSetDetach(
		// PDNS_RECORD pRecordList );
		[DllImport(Lib.Dnsapi, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("windns.h", MSDNShortId = "434dc11f-19a9-434f-a024-9cdbb560f24c")]
		public static extern IntPtr DnsRecordSetDetach([In] IntPtr pRecordList);

		/// <summary>The <c>DnsReleaseContextHandle</c> function releases memory used to store the credentials of a specific account.</summary>
		/// <param name="hContext">The credentials handle of a specific account.</param>
		/// <returns>None</returns>
		// https://docs.microsoft.com/en-us/windows/win32/api/windns/nf-windns-dnsreleasecontexthandle void DnsReleaseContextHandle( HANDLE
		// hContext );
		[DllImport(Lib.Dnsapi, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("windns.h", MSDNShortId = "08a5fa73-4583-4e87-bddb-09bfbfe1b36f")]
		public static extern void DnsReleaseContextHandle(HDNSCONTEXT hContext);

		/// <summary>The <c>DnsReplaceRecordSet</c> function type replaces an existing resource record (RR) set.</summary>
		/// <param name="pReplaceSet">
		/// A pointer to a DNS_RECORD structure that contains the RR set that replaces the existing set. The specified RR set is replaced
		/// with the contents of pNewSet. To delete a RR set, specify the set in pNewSet, but set RDATA to <c>NULL</c>.
		/// </param>
		/// <param name="Options">
		/// A value that contains a bitmap of DNS Update Options. Options can be combined and all options override <c>DNS_UPDATE_SECURITY_USE_DEFAULT</c>.
		/// </param>
		/// <param name="hContext">
		/// The handle to the credentials of a specific account. Used when secure dynamic update is required. This parameter is optional.
		/// </param>
		/// <param name="pExtraInfo">This parameter is reserved for future use and must be set to <c>NULL</c>.</param>
		/// <param name="pReserved">This parameter is reserved for future use and must be set to <c>NULL</c>.</param>
		/// <returns>
		/// Returns success confirmation upon successful completion. Otherwise, returns the appropriate DNS-specific error code as defined
		/// in Winerror.h.
		/// </returns>
		// https://docs.microsoft.com/en-us/windows/win32/api/windns/nf-windns-dnsreplacerecordseta DNS_STATUS DnsReplaceRecordSetA(
		// PDNS_RECORD pReplaceSet, DWORD Options, HANDLE hContext, PVOID pExtraInfo, PVOID pReserved );
		[DllImport(Lib.Dnsapi, SetLastError = false, EntryPoint = "DnsReplaceRecordSetW", CharSet = CharSet.Unicode)]
		[PInvokeData("windns.h", MSDNShortId = "7b99f440-72fa-4cf4-9267-98f436e99a50")]
		public static extern DNS_STATUS DnsReplaceRecordSet(in DNS_RECORD pReplaceSet, DNS_UPDATE Options, [Optional] HDNSCONTEXT hContext, IntPtr pExtraInfo = default, IntPtr pReserved = default);

		/// <summary>The <c>DnsReplaceRecordSet</c> function type replaces an existing resource record (RR) set.</summary>
		/// <param name="pReplaceSet">
		/// A pointer to a DNS_RECORD structure that contains the RR set that replaces the existing set. The specified RR set is replaced
		/// with the contents of pNewSet. To delete a RR set, specify the set in pNewSet, but set RDATA to <c>NULL</c>.
		/// </param>
		/// <param name="Options">
		/// A value that contains a bitmap of DNS Update Options. Options can be combined and all options override <c>DNS_UPDATE_SECURITY_USE_DEFAULT</c>.
		/// </param>
		/// <param name="hContext">
		/// The handle to the credentials of a specific account. Used when secure dynamic update is required. This parameter is optional.
		/// </param>
		/// <param name="pExtraInfo">This parameter is reserved for future use and must be set to <c>NULL</c>.</param>
		/// <param name="pReserved">This parameter is reserved for future use and must be set to <c>NULL</c>.</param>
		/// <returns>
		/// Returns success confirmation upon successful completion. Otherwise, returns the appropriate DNS-specific error code as defined
		/// in Winerror.h.
		/// </returns>
		// https://docs.microsoft.com/en-us/windows/win32/api/windns/nf-windns-dnsreplacerecordseta DNS_STATUS DnsReplaceRecordSetA(
		// PDNS_RECORD pReplaceSet, DWORD Options, HANDLE hContext, PVOID pExtraInfo, PVOID pReserved );
		[DllImport(Lib.Dnsapi, SetLastError = false, EntryPoint = "DnsReplaceRecordSetW", CharSet = CharSet.Unicode)]
		[PInvokeData("windns.h", MSDNShortId = "7b99f440-72fa-4cf4-9267-98f436e99a50")]
		public static extern DNS_STATUS DnsReplaceRecordSet([In] IntPtr pReplaceSet, DNS_UPDATE Options, [Optional] HDNSCONTEXT hContext, IntPtr pExtraInfo = default, IntPtr pReserved = default);

		/// <summary>Used to initiate a DNS-SD discovery for services running on the local network.</summary>
		/// <param name="pRequest">A pointer to a DNS_SERVICE_BROWSE_REQUEST structure that contains the browse request information.</param>
		/// <param name="pCancel">
		/// A pointer to a DNS_SERVICE_CANCEL structure that can be used to cancel a pending asynchronous browsing operation. This handle
		/// must remain valid until the query is canceled.
		/// </param>
		/// <returns>
		/// If successful, returns <c>DNS_REQUEST_PENDING</c>; otherwise, returns the appropriate DNS-specific error code as defined in .
		/// For extended error information, call GetLastError.
		/// </returns>
		/// <remarks>This function is asynchronous. As services are being discovered, the browse callback will be invoked for each result.</remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/windns/nf-windns-dnsservicebrowse DNS_STATUS DnsServiceBrowse(
		// PDNS_SERVICE_BROWSE_REQUEST pRequest, PDNS_SERVICE_CANCEL pCancel );
		[DllImport(Lib.Dnsapi, SetLastError = true, ExactSpelling = true)]
		[PInvokeData("windns.h")]
		public static extern DNS_STATUS DnsServiceBrowse(in DNS_SERVICE_BROWSE_REQUEST pRequest, out DNS_SERVICE_CANCEL pCancel);

		/// <summary>Used to cancel a running DNS-SD discovery query.</summary>
		/// <param name="pCancelHandle">
		/// A pointer to the DNS_SERVICE_CANCEL structure that was passed to the DnsServiceBrowse call that is to be cancelled.
		/// </param>
		/// <returns>
		/// If successful, returns <c>ERROR_SUCCESS</c>; otherwise, returns the appropriate DNS-specific error code as defined in . For
		/// extended error information, call GetLastError.
		/// </returns>
		/// <remarks>Canceling the query causes one further invocation of the browse callback, with status <c>ERROR_CANCELLED</c>.</remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/windns/nf-windns-dnsservicebrowsecancel DNS_STATUS DnsServiceBrowseCancel(
		// PDNS_SERVICE_CANCEL pCancelHandle );
		[DllImport(Lib.Dnsapi, SetLastError = true, ExactSpelling = true)]
		[PInvokeData("windns.h")]
		public static extern DNS_STATUS DnsServiceBrowseCancel(in DNS_SERVICE_CANCEL pCancelHandle);

		/// <summary>Used to build a DNS_SERVICE_INSTANCE structure from data that describes it.</summary>
		/// <param name="pServiceName">A string that represents the name of the service.</param>
		/// <param name="pHostName">A string that represents the name of the host of the service.</param>
		/// <param name="pIp4">A pointer to an <c>IP4_ADDRESS</c> structure that represents the service-associated IPv4 address.</param>
		/// <param name="pIp6">A pointer to an IP6_ADDRESS structure that represents the service-associated IPv6 address.</param>
		/// <param name="wPort">A value that represents the port on which the service is running.</param>
		/// <param name="wPriority">A value that represents the service priority.</param>
		/// <param name="wWeight">A value that represents the service weight.</param>
		/// <param name="dwPropertiesCount">The number of properties—defines the number of elements in the arrays of the and parameters.</param>
		/// <param name="keys">A pointer to an array of string values that represent the property keys.</param>
		/// <param name="values">A pointer to an array of string values that represent the corresponding property values.</param>
		/// <returns>
		/// A pointer to a newly allocated DNS_SERVICE_INSTANCE structure, built from the passed-in parameters. Your application is
		/// responsible for freeing the associated memory by calling DnsServiceFreeInstance.
		/// </returns>
		/// <remarks>The <c>dwInterfaceIndex</c> field of the returned structure is set to 0.</remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/windns/nf-windns-dnsserviceconstructinstance PDNS_SERVICE_INSTANCE
		// DnsServiceConstructInstance( PCWSTR pServiceName, PCWSTR pHostName, PIP4_ADDRESS pIp4, PIP6_ADDRESS pIp6, WORD wPort, WORD
		// wPriority, WORD wWeight, DWORD dwPropertiesCount, PCWSTR *keys, PCWSTR *values );
		[DllImport(Lib.Dnsapi, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("windns.h")]
		public static extern SafePDNS_SERVICE_INSTANCE DnsServiceConstructInstance([MarshalAs(UnmanagedType.LPWStr)] string pServiceName,
			[MarshalAs(UnmanagedType.LPWStr)] string pHostName, in IP4_ADDRESS pIp4, in IP6_ADDRESS pIp6, ushort wPort, ushort wPriority,
			ushort wWeight, uint dwPropertiesCount, [In, MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr)] string[] keys,
			[In, MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr)] string[] values);

		/// <summary>Used to build a DNS_SERVICE_INSTANCE structure from data that describes it.</summary>
		/// <param name="pServiceName">A string that represents the name of the service.</param>
		/// <param name="pHostName">A string that represents the name of the host of the service.</param>
		/// <param name="pIp4">A pointer to an <c>IP4_ADDRESS</c> structure that represents the service-associated IPv4 address.</param>
		/// <param name="pIp6">A pointer to an IP6_ADDRESS structure that represents the service-associated IPv6 address.</param>
		/// <param name="wPort">A value that represents the port on which the service is running.</param>
		/// <param name="wPriority">A value that represents the service priority.</param>
		/// <param name="wWeight">A value that represents the service weight.</param>
		/// <param name="dwPropertiesCount">The number of properties—defines the number of elements in the arrays of the and parameters.</param>
		/// <param name="keys">A pointer to an array of string values that represent the property keys.</param>
		/// <param name="values">A pointer to an array of string values that represent the corresponding property values.</param>
		/// <returns>
		/// A pointer to a newly allocated DNS_SERVICE_INSTANCE structure, built from the passed-in parameters. Your application is
		/// responsible for freeing the associated memory by calling DnsServiceFreeInstance.
		/// </returns>
		/// <remarks>The <c>dwInterfaceIndex</c> field of the returned structure is set to 0.</remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/windns/nf-windns-dnsserviceconstructinstance PDNS_SERVICE_INSTANCE
		// DnsServiceConstructInstance( PCWSTR pServiceName, PCWSTR pHostName, PIP4_ADDRESS pIp4, PIP6_ADDRESS pIp6, WORD wPort, WORD
		// wPriority, WORD wWeight, DWORD dwPropertiesCount, PCWSTR *keys, PCWSTR *values );
		[DllImport(Lib.Dnsapi, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("windns.h")]
		public static extern SafePDNS_SERVICE_INSTANCE DnsServiceConstructInstance([MarshalAs(UnmanagedType.LPWStr)] string pServiceName,
			[MarshalAs(UnmanagedType.LPWStr)] string pHostName, [In, Optional] IntPtr pIp4, [In, Optional] IntPtr pIp6, ushort wPort, ushort wPriority,
			ushort wWeight, uint dwPropertiesCount, [In, MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr)] string[] keys,
			[In, MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr)] string[] values);

		/// <summary>Used to copy a DNS_SERVICE_INSTANCE structure.</summary>
		/// <param name="pOrig">A pointer to the DNS_SERVICE_INSTANCE structure that is to be copied.</param>
		/// <returns>
		/// A pointer to a newly allocated DNS_SERVICE_INSTANCE structure that's a copy of . Your application is responsible for freeing the
		/// associated memory by calling DnsServiceFreeInstance.
		/// </returns>
		// https://docs.microsoft.com/en-us/windows/win32/api/windns/nf-windns-dnsservicecopyinstance PDNS_SERVICE_INSTANCE
		// DnsServiceCopyInstance( PDNS_SERVICE_INSTANCE pOrig );
		[DllImport(Lib.Dnsapi, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("windns.h")]
		public static extern SafePDNS_SERVICE_INSTANCE DnsServiceCopyInstance(SafePDNS_SERVICE_INSTANCE pOrig);

		/// <summary>Used to remove a registered service.</summary>
		/// <param name="pRequest">A pointer to the DNS_SERVICE_REGISTER_REQUEST structure that was used to register the service.</param>
		/// <param name="pCancel">Must be <see langword="null"/>.</param>
		/// <returns>
		/// If successful, returns <c>DNS_REQUEST_PENDING</c>; otherwise, returns the appropriate DNS-specific error code as defined in
		/// <c>Winerror.h</c>. For extended error information, call GetLastError.
		/// </returns>
		/// <remarks>
		/// This function is asynchronous. The callback will be invoked when the deregistration is completed, with a copy of the
		/// DNS_SERVICE_INSTANCE structure that was passed to DnsServiceRegister when the service was registered.
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/windns/nf-windns-dnsservicederegister DWORD DnsServiceDeRegister(
		// PDNS_SERVICE_REGISTER_REQUEST pRequest, PDNS_SERVICE_CANCEL pCancel );
		[DllImport(Lib.Dnsapi, SetLastError = true, ExactSpelling = true)]
		[PInvokeData("windns.h")]
		public static extern DNS_STATUS DnsServiceDeRegister(in DNS_SERVICE_REGISTER_REQUEST pRequest, in DNS_SERVICE_CANCEL pCancel);

		/// <summary>Used to free the resources associated with a DNS_SERVICE_INSTANCE structure.</summary>
		/// <param name="pInstance">A pointer to the DNS_SERVICE_INSTANCE structure that is to be freed.</param>
		/// <returns>None</returns>
		// https://docs.microsoft.com/en-us/windows/win32/api/windns/nf-windns-dnsservicefreeinstance void DnsServiceFreeInstance(
		// PDNS_SERVICE_INSTANCE pInstance );
		[DllImport(Lib.Dnsapi, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("windns.h")]
		public static extern void DnsServiceFreeInstance(IntPtr pInstance);

		/// <summary>Used to register a discoverable service on this device.</summary>
		/// <param name="pRequest">
		/// A pointer to a DNS_SERVICE_REGISTER_REQUEST structure that contains information about the service to be registered.
		/// </param>
		/// <param name="pCancel">
		/// An optional (it can be ) pointer to a DNS_SERVICE_CANCEL structure that can be used to cancel a pending asynchronous
		/// registration operation. If not , then this handle must remain valid until the registration is canceled.
		/// </param>
		/// <returns>
		/// If successful, returns <c>DNS_REQUEST_PENDING</c>; otherwise, returns the appropriate DNS-specific error code as defined in .
		/// For extended error information, call GetLastError.
		/// </returns>
		/// <remarks>
		/// This function is asynchronous. The registration callback will be called once the registration succeeds. To deregister the
		/// service, call DnsServiceDeRegister. The registration is tied to the lifetime of the calling process. If the process goes away,
		/// the service will be automatically deregistered.
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/windns/nf-windns-dnsserviceregister DWORD DnsServiceRegister(
		// PDNS_SERVICE_REGISTER_REQUEST pRequest, PDNS_SERVICE_CANCEL pCancel );
		[DllImport(Lib.Dnsapi, SetLastError = true, ExactSpelling = true)]
		[PInvokeData("windns.h")]
		public static extern DNS_STATUS DnsServiceRegister(in DNS_SERVICE_REGISTER_REQUEST pRequest, out DNS_SERVICE_CANCEL pCancel);

		/// <summary>Used to cancel a pending registration operation.</summary>
		/// <param name="pCancelHandle">
		/// A pointer to the DNS_SERVICE_CANCEL structure that was passed to the DnsServiceRegister call that is to be cancelled.
		/// </param>
		/// <returns>
		/// If successful, returns <c>ERROR_SUCCESS</c>. Returns <c>ERROR_CANCELLED</c> if the operation was already cancelled, or
		/// <c>ERROR_INVALID_PARAMETER</c> if the handle is invalid.
		/// </returns>
		// https://docs.microsoft.com/en-us/windows/win32/api/windns/nf-windns-dnsserviceregistercancel DWORD DnsServiceRegisterCancel(
		// PDNS_SERVICE_CANCEL pCancelHandle );
		[DllImport(Lib.Dnsapi, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("windns.h")]
		public static extern DNS_STATUS DnsServiceRegisterCancel(in DNS_SERVICE_CANCEL pCancelHandle);

		/// <summary>Used to obtain more information about a service advertised on the local network.</summary>
		/// <param name="pRequest">A pointer to a DNS_SERVICE_RESOLVE_REQUEST structure that contains the resolve request information.</param>
		/// <param name="pCancel">
		/// A pointer to a DNS_SERVICE_CANCEL structure that can be used to cancel a pending asynchronous resolve operation. This handle
		/// must remain valid until the query is canceled.
		/// </param>
		/// <returns>
		/// If successful, returns <c>DNS_REQUEST_PENDING</c>; otherwise, returns the appropriate DNS-specific error code as defined in .
		/// For extended error information, call GetLastError.
		/// </returns>
		/// <remarks>
		/// This function is asynchronous. Upon completion, the resolve callback will be invoked for each result. In contrast to
		/// DnsServiceBrowse—which returns the service name as a minimum— <c>DnsServiceResolve</c> can be used to retrieve additional
		/// information, such as hostname, IP address, and TEXT records.
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/windns/nf-windns-dnsserviceresolve DNS_STATUS DnsServiceResolve(
		// PDNS_SERVICE_RESOLVE_REQUEST pRequest, PDNS_SERVICE_CANCEL pCancel );
		[DllImport(Lib.Dnsapi, SetLastError = true, ExactSpelling = true)]
		[PInvokeData("windns.h")]
		public static extern DNS_STATUS DnsServiceResolve(in DNS_SERVICE_RESOLVE_REQUEST pRequest, out DNS_SERVICE_CANCEL pCancel);

		/// <summary>Used to cancel a running DNS-SD resolve query.</summary>
		/// <param name="pCancelHandle">
		/// A pointer to the DNS_SERVICE_CANCEL structure that was passed to the DnsServiceResolve call that is to be cancelled.
		/// </param>
		/// <returns>
		/// If successful, returns <c>ERROR_SUCCESS</c>; otherwise, returns the appropriate DNS-specific error code as defined in . For
		/// extended error information, call GetLastError.
		/// </returns>
		// https://docs.microsoft.com/en-us/windows/win32/api/windns/nf-windns-dnsserviceresolvecancel DNS_STATUS DnsServiceResolveCancel(
		// PDNS_SERVICE_CANCEL pCancelHandle );
		[DllImport(Lib.Dnsapi, SetLastError = true, ExactSpelling = true)]
		[PInvokeData("windns.h")]
		public static extern DNS_STATUS DnsServiceResolveCancel(in DNS_SERVICE_CANCEL pCancelHandle);

		/// <summary>Used to register a discoverable service on this device.</summary>
		/// <param name="pQueryRequest">A pointer to an MDNS_QUERY_REQUEST structure that contains information about the query to be performed.</param>
		/// <param name="pHandle">
		/// A pointer to an MDNS_QUERY_HANDLE structure that will be populated with the necessary data. This structure is to be passed later
		/// to DnsStopMulticastQuery to stop the query.
		/// </param>
		/// <returns>
		/// If successful, returns <c>ERROR_SUCCESS</c>; otherwise, returns the appropriate DNS-specific error code as defined in . For
		/// extended error information, call GetLastError.
		/// </returns>
		/// <remarks>
		/// This function is asynchronous. The query runs indefinitely, until DnsStopMulticastQuery is called. For each response from the
		/// network, the query callback will be invoked with the appropriate status and results.
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/windns/nf-windns-dnsstartmulticastquery DNS_STATUS DnsStartMulticastQuery(
		// PMDNS_QUERY_REQUEST pQueryRequest, PMDNS_QUERY_HANDLE pHandle );
		[DllImport(Lib.Dnsapi, SetLastError = true, ExactSpelling = true)]
		[PInvokeData("windns.h")]
		public static extern DNS_STATUS DnsStartMulticastQuery(in MDNS_QUERY_REQUEST pQueryRequest, out MDNS_QUERY_HANDLE pHandle);

		/// <summary>Used to stop a running DnsStartMulticastQuery operation.</summary>
		/// <param name="pHandle">
		/// A pointer to the MDNS_QUERY_HANDLE structure that was passed to the DnsStartMulticastQuery call that is to be stopped.
		/// </param>
		/// <returns>
		/// If successful, returns <c>ERROR_SUCCESS</c>; otherwise, returns the appropriate DNS-specific error code as defined in . For
		/// extended error information, call GetLastError.
		/// </returns>
		// https://docs.microsoft.com/en-us/windows/win32/api/windns/nf-windns-dnsstopmulticastquery DNS_STATUS DnsStopMulticastQuery(
		// PMDNS_QUERY_HANDLE pHandle );
		[DllImport(Lib.Dnsapi, SetLastError = true, ExactSpelling = true)]
		[PInvokeData("windns.h")]
		public static extern DNS_STATUS DnsStopMulticastQuery(in MDNS_QUERY_HANDLE pHandle);

		/// <summary>The <c>DnsValidateName</c> function validates the status of a specified DNS name.</summary>
		/// <param name="pszName"/>
		/// <param name="Format"/>
		/// <returns>The <c>DnsValidateName</c> function has the following possible return values:</returns>
		/// <remarks>
		/// <para>
		/// To verify the status of the Computer Host (single label), use the <c>DnsValidateName</c> function type with
		/// <c>DnsNameHostnameLabel</c> in Format.
		/// </para>
		/// <para>
		/// The <c>DnsValidateName</c> function works in a progression when determining whether an error exists with a given DNS name, and
		/// returns upon finding its first error. Therefore, a DNS name that has multiple, different errors may be reported as having the
		/// first error, and could be corrected and resubmitted, only then to find the second error.
		/// </para>
		/// <para>The <c>DnsValidateName</c> function searches for errors as follows:</para>
		/// <list type="number">
		/// <item>
		/// <term>Returns <c>ERROR_INVALID_NAME</c> if the DNS name:</term>
		/// </item>
		/// <item>
		/// <term>
		/// Next, <c>DnsValidateName</c> returns <c>DNS_ERROR_NUMERIC_NAME</c> if the full DNS name consists of only numeric characters
		/// (0-9) or the first label of the DNS name consists of only numeric characters (0-9), unless Format is set to DnsNameDomainLabel
		/// or DnsNameDomain.
		/// </term>
		/// </item>
		/// <item>
		/// <term>Then, <c>DnsValidateName</c> returns DNS_ERROR_NON_RFC_NAME if the DNS name:</term>
		/// </item>
		/// <item>
		/// <term>Next, <c>DnsValidateName</c> returns <c>DNS_ERROR_INVALID_NAME_CHAR</c> if the DNS name:</term>
		/// </item>
		/// </list>
		/// <para>
		/// <c>Note</c> If <c>DnsValidateName</c> returns <c>DNS_ERROR_NON_RFC_NAME</c>, the error should be handled as a warning that not
		/// all DNS servers will accept the name. When this error is received, note that the DNS Server does accept the submitted name, if
		/// appropriately configured (default configuration accepts the name as submitted when <c>DNS_ERROR_NON_RFC_NAME</c> is returned),
		/// but other DNS server software may not. Windows DNS servers do handle <c>NON_RFC_NAMES</c>.If <c>DnsValidateName</c> returns any
		/// of the following errors, pszName should be handled as an invalid host name:
		/// </para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/windns/nf-windns-dnsvalidatename_w DNS_STATUS DnsValidateName_W( PCWSTR
		// pszName, DNS_NAME_FORMAT Format );
		[DllImport(Lib.Dnsapi, SetLastError = false, EntryPoint = "DnsValidateName_W", CharSet = CharSet.Unicode)]
		[PInvokeData("windns.h", MSDNShortId = "efdbd217-6936-42c1-a1eb-8655a62513ee")]
		public static extern DNS_STATUS DnsValidateName([MarshalAs(UnmanagedType.LPWStr)] string pszName, DNS_NAME_FORMAT Format);

		/// <summary>The <c>DnsValidateServerStatus</c> function validates an IP address as a suitable DNS server.</summary>
		/// <param name="server">A pointer to a SOCKADDR that contains the DNS server IPv4 or IPv6 address to be examined.</param>
		/// <param name="queryName">
		/// A pointer to a Unicode string that represents the fully qualified domain name (FQDN) of the owner of the record set that is queried.
		/// </param>
		/// <param name="serverStatus">
		/// <para>A pointer to a DWORD that represents the query validation status.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>ERROR_SUCCESS</term>
		/// <term>No errors. The call was successful.</term>
		/// </item>
		/// <item>
		/// <term>DNS_VALSVR_ERROR_INVALID_ADDR</term>
		/// <term>server IP address was invalid.</term>
		/// </item>
		/// <item>
		/// <term>DNS_VALSVR_ERROR_INVALID_NAME</term>
		/// <term>queryName FQDN was invalid.</term>
		/// </item>
		/// <item>
		/// <term>DNS_VALSVR_ERROR_UNREACHABLE</term>
		/// <term>DNS server was unreachable.</term>
		/// </item>
		/// <item>
		/// <term>DNS_VALSVR_ERROR_NO_RESPONSE</term>
		/// <term>Timeout waiting for the DNS server response.</term>
		/// </item>
		/// <item>
		/// <term>DNS_VALSVR_ERROR_NO_AUTH</term>
		/// <term>DNS server was not authoritative or queryName was not found.</term>
		/// </item>
		/// <item>
		/// <term>DNS_VALSVR_ERROR_REFUSED</term>
		/// <term>DNS server refused the query.</term>
		/// </item>
		/// <item>
		/// <term>DNS_VALSVR_ERROR_NO_TCP</term>
		/// <term>
		/// The TCP query did not return ERROR_SUCCESS after the validation system had already completed a successful query to the DNS
		/// server using UDP.
		/// </term>
		/// </item>
		/// <item>
		/// <term>DNS_VALSVR_ERROR_UNKNOWN</term>
		/// <term>An unknown error occurred.</term>
		/// </item>
		/// </list>
		/// </param>
		/// <returns>The <c>DnsValidateServerStatus</c> function has the following possible return values:</returns>
		// https://docs.microsoft.com/en-us/windows/win32/api/windns/nf-windns-dnsvalidateserverstatus DNS_STATUS DnsValidateServerStatus(
		// PSOCKADDR server, PCWSTR queryName, PDWORD serverStatus );
		[DllImport(Lib.Dnsapi, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("windns.h", MSDNShortId = "5b362d05-87b2-44dd-8198-bcb5ab5a64f6")]
		public static extern DNS_STATUS DnsValidateServerStatus([In] SOCKADDR server, [Optional, MarshalAs(UnmanagedType.LPWStr)] string queryName, out DnsServerStatus serverStatus);

		/// <summary>
		/// The <c>DnsWriteQuestionToBuffer</c> function type creates a DNS query message and stores it in a DNS_MESSAGE_BUFFER structure.
		/// </summary>
		/// <param name="pDnsBuffer">A pointer to a DNS_MESSAGE_BUFFER structure that contains a DNS query message stored in a buffer.</param>
		/// <param name="pdwBufferSize">
		/// The size, in bytes, of the buffer allocated to store pDnsBuffer. If the buffer size is insufficient to contain the message,
		/// <c>FALSE</c> is returned and pdwBufferSize contains the minimum required buffer size.
		/// </param>
		/// <param name="pszName">A pointer to a string that represents the name of the owner of the record set being queried.</param>
		/// <param name="wType">
		/// A value that represents the RR DNS Record Type. <c>wType</c> determines the format of <c>Data</c>. For example, if the value of
		/// <c>wType</c> is <c>DNS_TYPE_A</c>, the data type of <c>Data</c> is DNS_A_DATA.
		/// </param>
		/// <param name="Xid">A value that specifies the unique DNS query identifier.</param>
		/// <param name="fRecursionDesired">
		/// A BOOL that specifies whether recursive name query should be used by the DNS name server. Set to <c>TRUE</c> to request
		/// recursive name query, <c>FALSE</c> to request iterative name query.
		/// </param>
		/// <returns>Returns <c>TRUE</c> upon successful execution, otherwise <c>FALSE</c>.</returns>
		// https://docs.microsoft.com/en-us/windows/win32/api/windns/nf-windns-dnswritequestiontobuffer_w BOOL DnsWriteQuestionToBuffer_W(
		// PDNS_MESSAGE_BUFFER pDnsBuffer, PDWORD pdwBufferSize, PCWSTR pszName, WORD wType, WORD Xid, BOOL fRecursionDesired );
		[DllImport(Lib.Dnsapi, SetLastError = true, EntryPoint = "DnsWriteQuestionToBuffer_W", CharSet = CharSet.Unicode)]
		[PInvokeData("windns.h", MSDNShortId = "9aa853aa-d9b5-41e3-a82a-c25de199924d")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool DnsWriteQuestionToBuffer([In, Out] IntPtr pDnsBuffer, ref uint pdwBufferSize, [MarshalAs(UnmanagedType.LPWStr)] string pszName,
			DNS_TYPE wType, ushort Xid, [MarshalAs(UnmanagedType.Bool)] bool fRecursionDesired);

		/// <summary>Provides a handle to a DNS Context.</summary>
		[StructLayout(LayoutKind.Sequential)]
		public struct HDNSCONTEXT : IHandle
		{
			private IntPtr handle;

			/// <summary>Initializes a new instance of the <see cref="HDNSCONTEXT"/> struct.</summary>
			/// <param name="preexistingHandle">An <see cref="IntPtr"/> object that represents the pre-existing handle to use.</param>
			public HDNSCONTEXT(IntPtr preexistingHandle) => handle = preexistingHandle;

			/// <summary>Returns an invalid handle by instantiating a <see cref="HDNSCONTEXT"/> object with <see cref="IntPtr.Zero"/>.</summary>
			public static HDNSCONTEXT NULL => new HDNSCONTEXT(IntPtr.Zero);

			/// <summary>Gets a value indicating whether this instance is a null handle.</summary>
			public bool IsNull => handle == IntPtr.Zero;

			/// <summary>Performs an explicit conversion from <see cref="HDNSCONTEXT"/> to <see cref="IntPtr"/>.</summary>
			/// <param name="h">The handle.</param>
			/// <returns>The result of the conversion.</returns>
			public static explicit operator IntPtr(HDNSCONTEXT h) => h.handle;

			/// <summary>Performs an implicit conversion from <see cref="IntPtr"/> to <see cref="HDNSCONTEXT"/>.</summary>
			/// <param name="h">The pointer to a handle.</param>
			/// <returns>The result of the conversion.</returns>
			public static implicit operator HDNSCONTEXT(IntPtr h) => new HDNSCONTEXT(h);

			/// <summary>Implements the operator !=.</summary>
			/// <param name="h1">The first handle.</param>
			/// <param name="h2">The second handle.</param>
			/// <returns>The result of the operator.</returns>
			public static bool operator !=(HDNSCONTEXT h1, HDNSCONTEXT h2) => !(h1 == h2);

			/// <summary>Implements the operator ==.</summary>
			/// <param name="h1">The first handle.</param>
			/// <param name="h2">The second handle.</param>
			/// <returns>The result of the operator.</returns>
			public static bool operator ==(HDNSCONTEXT h1, HDNSCONTEXT h2) => h1.Equals(h2);

			/// <inheritdoc/>
			public override bool Equals(object obj) => obj is HDNSCONTEXT h ? handle == h.handle : false;

			/// <inheritdoc/>
			public override int GetHashCode() => handle.GetHashCode();

			/// <inheritdoc/>
			public IntPtr DangerousGetHandle() => handle;
		}

		/// <summary>Provides a <see cref="SafeHandle"/> for a list of allocated <c>DNS_CACHE_ENTRY</c> values that is disposed using <see cref="DnsFree"/>.</summary>
		public class SafeDnsCacheDataTable : SafeHANDLE, IEnumerable<DNS_CACHE_ENTRY>
		{
			/// <summary>Initializes a new instance of the <see cref="SafeDnsCacheDataTable"/> 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 SafeDnsCacheDataTable(IntPtr preexistingHandle, bool ownsHandle = true) : base(preexistingHandle, ownsHandle) { }

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

			/// <summary>Returns an enumerator that iterates through the collection.</summary>
			/// <returns>A <see cref="T:System.Collections.Generic.IEnumerator`1"/> that can be used to iterate through the collection.</returns>
			public IEnumerator<DNS_CACHE_ENTRY> GetEnumerator() => handle.LinkedListToIEnum<DNS_CACHE_ENTRY>(r => r.pNext).GetEnumerator();

			/// <summary>Returns an enumerator that iterates through a collection.</summary>
			/// <returns>An <see cref="T:System.Collections.IEnumerator"/> object that can be used to iterate through the collection.</returns>
			IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();

			/// <inheritdoc/>
			protected override bool InternalReleaseHandle()
			{
				// From https://stackoverflow.com/questions/31889957/memory-leak-when-using-dnsgetcachedatatable
				var p = handle;
				while (p != IntPtr.Zero)
				{
					var s = p.ToStructure<DNS_CACHE_ENTRY>();
					DnsFree((IntPtr)s.pszName, DNS_FREE_TYPE.DnsFreeFlat);
					DnsFree(p, DNS_FREE_TYPE.DnsFreeFlat);
					p = s.pNext;
				}
				return true;
			}
		}

		/// <summary>Provides a <see cref="SafeHandle"/> for a DNS record list that is disposed using <see cref="DnsRecordListFree"/>.</summary>
		public class SafeDnsRecordList : SafeHANDLE, IEnumerable<DNS_RECORD>
		{
			/// <summary>Initializes a new instance of the <see cref="SafeDnsRecordList"/> 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 SafeDnsRecordList(IntPtr preexistingHandle, bool ownsHandle = true) : base(preexistingHandle, ownsHandle) { }

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

			/// <summary>Performs an implicit conversion from <see cref="SafeDnsRecordList"/> to <see cref="IntPtr"/>.</summary>
			/// <param name="h">The safe handle instance.</param>
			/// <returns>The result of the conversion.</returns>
			public static implicit operator IntPtr(SafeDnsRecordList h) => h.handle;

			/// <summary>Returns an enumerator that iterates through the collection.</summary>
			/// <returns>A <see cref="T:System.Collections.Generic.IEnumerator`1"/> that can be used to iterate through the collection.</returns>
			/// <exception cref="NotImplementedException"></exception>
			public IEnumerator<DNS_RECORD> GetEnumerator() => handle.LinkedListToIEnum<DNS_RECORD>(r => r.pNext).GetEnumerator();

			/// <summary>Gets a sequence of pointers to each of the records.</summary>
			/// <returns>Record pointers.</returns>
			public IEnumerable<IntPtr> GetRecordPointers()
			{
				var p = handle;
				while (p != IntPtr.Zero)
				{
					yield return p;
					p = p.ToStructure<DNS_RECORD>().pNext;
				}
			}

			/// <summary>Returns an enumerator that iterates through a collection.</summary>
			/// <returns>An <see cref="T:System.Collections.IEnumerator"/> object that can be used to iterate through the collection.</returns>
			IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();

			/// <inheritdoc/>
			protected override bool InternalReleaseHandle() { DnsRecordListFree(handle); return true; }
		}

		/// <summary>Provides a <see cref="SafeHandle"/> for <see cref="HDNSCONTEXT"/> that is disposed using <see cref="DnsReleaseContextHandle"/>.</summary>
		public class SafeHDNSCONTEXT : SafeHANDLE
		{
			/// <summary>Initializes a new instance of the <see cref="SafeHDNSCONTEXT"/> 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 SafeHDNSCONTEXT(IntPtr preexistingHandle, bool ownsHandle = true) : base(preexistingHandle, ownsHandle) { }

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

			/// <summary>Performs an explicit conversion from <see cref="SafeHDNSCONTEXT"/> to <see cref="IntPtr"/>.</summary>
			/// <param name="h">The safe handle instance.</param>
			/// <returns>The resulting <see cref="IntPtr"/> instance from the conversion.</returns>
			public static explicit operator IntPtr(SafeHDNSCONTEXT h) => h.handle;

			/// <summary>Performs an implicit conversion from <see cref="SafeHDNSCONTEXT"/> to <see cref="HDNSCONTEXT"/>.</summary>
			/// <param name="h">The safe handle instance.</param>
			/// <returns>The result of the conversion.</returns>
			public static implicit operator HDNSCONTEXT(SafeHDNSCONTEXT h) => h.handle;

			/// <inheritdoc/>
			protected override bool InternalReleaseHandle() { DnsReleaseContextHandle(handle); return true; }
		}

		internal class DnsProxyStringMem : ISimpleMemoryMethods
		{
			private bool self = false;
			public Func<int, IntPtr> AllocMem => s => { self = true; return Marshal.AllocCoTaskMem(s); };
			public Action<IntPtr> FreeMem => p => { if (self) Marshal.FreeCoTaskMem(p); else DnsFreeProxyName(p); };
		}
	}
}