using System;
using System.Net;
using System.Runtime.InteropServices;
using Vanara.Extensions;
using Vanara.InteropServices;

namespace Vanara.PInvoke
{
	public static partial class Ws2_32
	{
		/// <summary>Flags that indicate options used in the GetAddrInfoW function.</summary>
		[PInvokeData("ws2def.h", MSDNShortId = "a4896eac-68ae-4a08-8647-36be65fe4478")]
		[Flags]
		public enum ADDRINFO_FLAGS : uint
		{
			/// <summary>The socket address will be used in a call to the bindfunction.</summary>
			AI_PASSIVE = 0x01,

			/// <summary>The canonical name is returned in the first ai_canonname member.</summary>
			AI_CANONNAME = 0x02,

			/// <summary>The nodename parameter passed to the GetAddrInfoW function must be a numeric string.</summary>
			AI_NUMERICHOST = 0x04,

			/// <summary>Servicename must be a numeric port number.</summary>
			AI_NUMERICSERV = 0x08,

			/// <summary>
			/// If this bit is set, a request is made for IPv6 addresses and IPv4 addresses with AI_V4MAPPED.
			/// <para>This option is supported on Windows Vista and later.</para>
			/// </summary>
			AI_ALL = 0x0100,

			/// <summary>
			/// The GetAddrInfoW will resolve only if a global address is configured. The IPv6 and IPv4 loopback address is not considered a
			/// valid global address. This option is only supported on Windows Vista and later.
			/// </summary>
			AI_ADDRCONFIG = 0x0400,

			/// <summary>
			/// If the GetAddrInfoW request for an IPv6 addresses fails, a name service request is made for IPv4 addresses and these
			/// addresses are converted to IPv4-mapped IPv6 address format.
			/// <para>This option is supported on Windows Vista and later.</para>
			/// </summary>
			AI_V4MAPPED = 0x0800,

			/// <summary>
			/// The address information can be from a non-authoritative namespace provider.
			/// <para>This option is only supported on Windows Vista and later for the NS_EMAIL namespace.</para>
			/// </summary>
			AI_NON_AUTHORITATIVE = 0x04000,

			/// <summary>
			/// The address information is from a secure channel.
			/// <para>This option is only supported on Windows Vista and later for the NS_EMAIL namespace.</para>
			/// </summary>
			AI_SECURE = 0x08000,

			/// <summary>
			/// The address information is for a preferred name for a user.
			/// <para>This option is only supported on Windows Vista and later for the NS_EMAIL namespace.</para>
			/// </summary>
			AI_RETURN_PREFERRED_NAMES = 0x010000,

			/// <summary>
			/// If a flat name (single label) is specified, GetAddrInfoW will return the fully qualified domain name that the name
			/// eventually resolved to. The fully qualified domain name is returned in the ai_canonname member.
			/// <para>
			/// This is different than AI_CANONNAME bit flag that returns the canonical name registered in DNS which may be different than
			/// the fully qualified domain name that the flat name resolved to.
			/// </para>
			/// <para>
			/// Only one of the AI_FQDN and AI_CANONNAME bits can be set. The GetAddrInfoW function will fail if both flags are present with EAI_BADFLAGS.
			/// </para>
			/// <para>This option is supported on Windows 7, Windows Server 2008 R2, and later.</para>
			/// </summary>
			AI_FQDN = 0x00020000,

			/// <summary>
			/// A hint to the namespace provider that the hostname being queried is being used in a file share scenario. The namespace
			/// provider may ignore this hint.
			/// <para>This option is supported on Windows 7, Windows Server 2008 R2, and later.</para>
			/// </summary>
			AI_FILESERVER = 0x00040000,

			/// <summary>
			/// Disable the automatic International Domain Name encoding using Punycode in the name resolution functions called by the
			/// GetAddrInfoW function.
			/// <para>This option is supported on Windows 8, Windows Server 2012, and later.</para>
			/// </summary>
			AI_DISABLE_IDN_ENCODING = 0x00080000,

			/// <summary>Indicates this is extended ADDRINFOEX(2/..) struct</summary>
			AI_EXTENDED = 0x80000000,

			/// <summary>Request resolution handle</summary>
			AI_RESOLUTION_HANDLE = 0x40000000,
		}

		/// <summary>Customize processing of the GetNameInfoW function.</summary>
		[PInvokeData("ws2def.h", MSDNShortId = "5630a49a-c182-440c-ad54-6ff3ba4274c6")]
		public enum NI
		{
			/// <summary>Results in local hosts having only their Relative Distinguished Name (RDN) returned in the pNodeBuffer parameter.</summary>
			NI_NOFQDN = 0x01  /* Only return nodename portion for local hosts */,

			/// <summary>
			/// Returns the numeric form of the host name instead of its name. The numeric form of the host name is also returned if the
			/// host name cannot be resolved by DNS.
			/// </summary>
			NI_NUMERICHOST = 0x02  /* Return numeric form of the host's address */,

			/// <summary>A host name that cannot be resolved by the DNS results in an error.</summary>
			NI_NAMEREQD = 0x04  /* Error if the host's name not in DNS */,

			/// <summary>
			/// Returns the port number of the service instead of its name. Also, if a host name is not found for an IP address (127.0.0.2,
			/// for example), the hostname is returned as the IP address.
			/// </summary>
			NI_NUMERICSERV = 0x08  /* Return numeric form of the service (port #) */,

			/// <summary>
			/// Indicates that the service is a datagram service. This flag is necessary for the few services that provide different port
			/// numbers for UDP and TCP service.
			/// </summary>
			NI_DGRAM = 0x10  /* Service is a datagram service */,
		}

		/// <summary>The scope of the IPv6 transport address.</summary>
		[PInvokeData("ws2def.h")]
		public enum SCOPE_LEVEL
		{
			/// <summary>The transport address has interface-local scope.</summary>
			ScopeLevelInterface = 1,

			/// <summary>The transport address has link-local scope.</summary>
			ScopeLevelLink = 2,

			/// <summary>The transport address has subnet-local scope.</summary>
			ScopeLevelSubnet = 3,

			/// <summary>The transport address has admin-local scope.</summary>
			ScopeLevelAdmin = 4,

			/// <summary>The transport address has site-local scope.</summary>
			ScopeLevelSite = 5,

			/// <summary>The transport address has organization-local scope.</summary>
			ScopeLevelOrganization = 8,

			/// <summary>The transport address has global scope.</summary>
			ScopeLevelGlobal = 14,

			/// <summary>The scope level count.</summary>
			ScopeLevelCount = 16
		}

		/// <summary>
		/// The addrinfoex2 structure is used by the GetAddrInfoEx function to hold host address information when both a canonical name and
		/// a fully qualified domain name have been requested.
		/// </summary>
		// https://docs.microsoft.com/en-us/windows/win32/api/ws2def/ns-ws2def-addrinfoex2w typedef struct addrinfoex2W { int ai_flags; int
		// ai_family; int ai_socktype; int ai_protocol; size_t ai_addrlen; PWSTR ai_canonname; struct sockaddr *ai_addr; void *ai_blob;
		// size_t ai_bloblen; LPGUID ai_provider; struct addrinfoex2W *ai_next; int ai_version; PWSTR ai_fqdn; } ADDRINFOEX2W,
		// *PADDRINFOEX2W, *LPADDRINFOEX2W;
		[PInvokeData("ws2def.h", MSDNShortId = "9CB33347-A838-473D-B5CD-1149D6632CF2")]
		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
		public struct ADDRINFOEX2W
		{
			/// <summary>
			/// <para>Flags that indicate options used in the GetAddrInfoEx function.</para>
			/// <para>
			/// Supported values for the <c>ai_flags</c> member are defined in the Winsock2.h include file and can be a combination of the
			/// following options.
			/// </para>
			/// <list type="table">
			/// <listheader>
			/// <term>Value</term>
			/// <term>Meaning</term>
			/// </listheader>
			/// <item>
			/// <term>AI_PASSIVE 0x01</term>
			/// <term>The socket address will be used in a call to the bindfunction.</term>
			/// </item>
			/// <item>
			/// <term>AI_CANONNAME 0x02</term>
			/// <term>The canonical name is returned in the first ai_canonname member.</term>
			/// </item>
			/// <item>
			/// <term>AI_NUMERICHOST 0x04</term>
			/// <term>The nodename parameter passed to the GetAddrInfoEx function must be a numeric string.</term>
			/// </item>
			/// <item>
			/// <term>AI_ALL 0x0100</term>
			/// <term>
			/// If this bit is set, a request is made for IPv6 addresses and IPv4 addresses with AI_V4MAPPED. This option is supported on
			/// Windows Vista and later.
			/// </term>
			/// </item>
			/// <item>
			/// <term>AI_ADDRCONFIG 0x0400</term>
			/// <term>
			/// The GetAddrInfoEx will resolve only if a global address is configured. The IPv6 and IPv4 loopback address is not considered
			/// a valid global address. This option is supported on Windows Vista and later.
			/// </term>
			/// </item>
			/// <item>
			/// <term>AI_V4MAPPED 0x0800</term>
			/// <term>
			/// If the GetAddrInfoEx request for an IPv6 addresses fails, a name service request is made for IPv4 addresses and these
			/// addresses are converted to IPv4-mapped IPv6 address format. This option is supported on Windows Vista and later.
			/// </term>
			/// </item>
			/// <item>
			/// <term>AI_NON_AUTHORITATIVE 0x04000</term>
			/// <term>
			/// The address information is from non-authoritative results. When this option is set in the pHints parameter of GetAddrInfoEx,
			/// the NS_EMAIL namespace provider returns both authoritative and non-authoritative results. If this option is not set, then
			/// only authoritative results are returned. This option is only supported on Windows Vista and later for the NS_EMAIL namespace.
			/// </term>
			/// </item>
			/// <item>
			/// <term>AI_SECURE 0x08000</term>
			/// <term>
			/// The address information is from a secure channel. If the AI_SECURE bit is set, the NS_EMAIL namespace provider will return
			/// results that were obtained with enhanced security to minimize possible spoofing. When this option is set in the pHints
			/// parameter of GetAddrInfoEx, the NS_EMAIL namespace provider returns only results that were obtained with enhanced security
			/// to minimize possible spoofing. This option is only supported on Windows Vista and later for the NS_EMAIL namespace.
			/// </term>
			/// </item>
			/// <item>
			/// <term>AI_RETURN_PREFERRED_NAMES 0x010000</term>
			/// <term>
			/// The address information is for a preferred names for publication with a specific namespace. When this option is set in the
			/// pHints parameter of GetAddrInfoEx, no name should be provided in the pName parameter and the NS_EMAIL namespace provider
			/// will return preferred names for publication. This option is only supported on Windows Vista and later for the NS_EMAIL namespace.
			/// </term>
			/// </item>
			/// <item>
			/// <term>AI_FQDN 0x00020000</term>
			/// <term>
			/// The fully qualified domain name is returned in the first ai_fqdn member. When this option is set in the pHints parameter of
			/// GetAddrInfoEx and a flat name (single label) is specified in the pName parameter, the fully qualified domain name that the
			/// name eventually resolved to will be returned. This option is supported on Windows 7, Windows Server 2008 R2, and later.
			/// </term>
			/// </item>
			/// <item>
			/// <term>AI_FILESERVER 0x00040000</term>
			/// <term>
			/// A hint to the namespace provider that the hostname being queried is being used in a file share scenario. The namespace
			/// provider may ignore this hint. This option is supported on Windows 7, Windows Server 2008 R2, and later.
			/// </term>
			/// </item>
			/// <item>
			/// <term>AI_DISABLE_IDN_ENCODING 0x00080000</term>
			/// <term>
			/// Disable the automatic International Domain Name encoding using Punycode in the name resolution functions called by the
			/// GetAddrInfoEx function. This option is supported on Windows 8, Windows Server 2012, and later.
			/// </term>
			/// </item>
			/// </list>
			/// </summary>
			public ADDRINFO_FLAGS ai_flags;

			private uint _ai_family;

			/// <summary>
			/// <para>Type: <c>int</c></para>
			/// <para>The address family. Possible values for the address family are defined in the Winsock2.h include file.</para>
			/// <para>
			/// On the Windows SDK released for Windows Vista and later,, the organization of header files has changed and the possible
			/// values for the address family are defined in the Ws2def.h header file. Note that the Ws2def.h header file is automatically
			/// included in Winsock2.h, and should never be used directly.
			/// </para>
			/// <para>
			/// The values currently supported are <c>AF_INET</c> or <c>AF_INET6</c>, which are the Internet address family formats for IPv4
			/// and IPv6. Other options for address family ( <c>AF_NETBIOS</c> for use with NetBIOS, for example) are supported if a Windows
			/// Sockets service provider for the address family is installed. Note that the values for the AF_ address family and PF_
			/// protocol family constants are identical (for example, <c>AF_UNSPEC</c> and <c>PF_UNSPEC</c>), so either constant can be used.
			/// </para>
			/// <para>The table below lists common values for the address family although many other values are possible.</para>
			/// <list type="table">
			/// <listheader>
			/// <term>Value</term>
			/// <term>Meaning</term>
			/// </listheader>
			/// <item>
			/// <term>AF_UNSPEC 0</term>
			/// <term>The address family is unspecified.</term>
			/// </item>
			/// <item>
			/// <term>AF_INET 2</term>
			/// <term>The Internet Protocol version 4 (IPv4) address family.</term>
			/// </item>
			/// <item>
			/// <term>AF_NETBIOS 17</term>
			/// <term>The NetBIOS address family. This address family is only supported if a Windows Sockets provider for NetBIOS is installed.</term>
			/// </item>
			/// <item>
			/// <term>AF_INET6 23</term>
			/// <term>The Internet Protocol version 6 (IPv6) address family.</term>
			/// </item>
			/// <item>
			/// <term>AF_IRDA 26</term>
			/// <term>
			/// The Infrared Data Association (IrDA) address family. This address family is only supported if the computer has an infrared
			/// port and driver installed.
			/// </term>
			/// </item>
			/// <item>
			/// <term>AF_BTH 32</term>
			/// <term>
			/// The Bluetooth address family. This address family is only supported if a Bluetooth adapter is installed on Windows Server
			/// 2003 or later.
			/// </term>
			/// </item>
			/// </list>
			/// </summary>
			public ADDRESS_FAMILY ai_family { get => (ADDRESS_FAMILY)_ai_family; set => _ai_family = (ushort)value; }

			/// <summary>
			/// <para>The socket type. Possible values for the socket type are defined in the Winsock2.h include file.</para>
			/// <para>The following table lists the possible values for the socket type supported for Windows Sockets 2:</para>
			/// <list type="table">
			/// <listheader>
			/// <term>Value</term>
			/// <term>Meaning</term>
			/// </listheader>
			/// <item>
			/// <term>SOCK_STREAM 1</term>
			/// <term>
			/// Provides sequenced, reliable, two-way, connection-based byte streams with an OOB data transmission mechanism. Uses the
			/// Transmission Control Protocol (TCP) for the Internet address family (AF_INET or AF_INET6). If the ai_family member is
			/// AF_IRDA, then SOCK_STREAM is the only supported socket type.
			/// </term>
			/// </item>
			/// <item>
			/// <term>SOCK_DGRAM 2</term>
			/// <term>
			/// Supports datagrams, which are connectionless, unreliable buffers of a fixed (typically small) maximum length. Uses the User
			/// Datagram Protocol (UDP) for the Internet address family (AF_INET or AF_INET6).
			/// </term>
			/// </item>
			/// <item>
			/// <term>SOCK_RAW 3</term>
			/// <term>
			/// Provides a raw socket that allows an application to manipulate the next upper-layer protocol header. To manipulate the IPv4
			/// header, the IP_HDRINCL socket option must be set on the socket. To manipulate the IPv6 header, the IPV6_HDRINCL socket
			/// option must be set on the socket.
			/// </term>
			/// </item>
			/// <item>
			/// <term>SOCK_RDM 4</term>
			/// <term>
			/// Provides a reliable message datagram. An example of this type is the Pragmatic General Multicast (PGM) multicast protocol
			/// implementation in Windows, often referred to as reliable multicast programming.
			/// </term>
			/// </item>
			/// <item>
			/// <term>SOCK_SEQPACKET 5</term>
			/// <term>Provides a pseudo-stream packet based on datagrams.</term>
			/// </item>
			/// </list>
			/// <para>
			/// In Windows Sockets 2, new socket types were introduced. An application can dynamically discover the attributes of each
			/// available transport protocol through the WSAEnumProtocols function. So an application can determine the possible socket type
			/// and protocol options for an address family and use this information when specifying this parameter. Socket type definitions
			/// in the Winsock2.h and Ws2def.h header files will be periodically updated as new socket types, address families, and
			/// protocols are defined.
			/// </para>
			/// <para>In Windows Sockets 1.1, the only possible socket types are <c>SOCK_DATAGRAM</c> and <c>SOCK_STREAM</c>.</para>
			/// </summary>
			public SOCK ai_socktype;

			/// <summary>
			/// <para>
			/// The protocol type. The possible options are specific to the address family and socket type specified. Possible values for
			/// the <c>ai_protocol</c> are defined in Winsock2.h and the Wsrm.h header files.
			/// </para>
			/// <para>
			/// On the Windows SDK released for Windows Vista and later,, the organization of header files has changed and this member can
			/// be one of the values from the <c>IPPROTO</c> enumeration type defined in the Ws2def.h header file. Note that the Ws2def.h
			/// header file is automatically included in Winsock2.h, and should never be used directly.
			/// </para>
			/// <para>
			/// If a value of 0 is specified for <c>ai_protocol</c>, the caller does not wish to specify a protocol and the service provider
			/// will choose the <c>ai_protocol</c> to use. For protocols other than IPv4 and IPv6, set <c>ai_protocol</c> to zero.
			/// </para>
			/// <para>The following table lists common values for the <c>ai_protocol</c> member although many other values are possible.</para>
			/// <list type="table">
			/// <listheader>
			/// <term>Value</term>
			/// <term>Meaning</term>
			/// </listheader>
			/// <item>
			/// <term>IPPROTO_TCP 6</term>
			/// <term>
			/// The Transmission Control Protocol (TCP). This is a possible value when the ai_family member is AF_INET or AF_INET6 and the
			/// ai_socktype member is SOCK_STREAM.
			/// </term>
			/// </item>
			/// <item>
			/// <term>IPPROTO_UDP 17</term>
			/// <term>
			/// The User Datagram Protocol (UDP). This is a possible value when the ai_family member is AF_INET or AF_INET6 and the type
			/// parameter is SOCK_DGRAM.
			/// </term>
			/// </item>
			/// <item>
			/// <term>IPPROTO_RM 113</term>
			/// <term>
			/// The PGM protocol for reliable multicast. This is a possible value when the ai_family member is AF_INET and the ai_socktype
			/// member is SOCK_RDM. On the Windows SDK released for Windows Vista and later, this value is also called IPPROTO_PGM.
			/// </term>
			/// </item>
			/// </list>
			/// <para>If the <c>ai_family</c> member is <c>AF_IRDA</c>, then the <c>ai_protocol</c> must be 0.</para>
			/// </summary>
			public IPPROTO ai_protocol;

			/// <summary>The length, in bytes, of the buffer pointed to by the <c>ai_addr</c> member.</summary>
			public SizeT ai_addrlen;

			/// <summary>The canonical name for the host.</summary>
			public StrPtrUni ai_canonname;

			/// <summary>
			/// A pointer to a sockaddr structure. The <c>ai_addr</c> member in each returned <c>addrinfoex2</c> structure points to a
			/// filled-in socket address structure. The length, in bytes, of each returned <c>addrinfoex2</c> structure is specified in the
			/// <c>ai_addrlen</c> member.
			/// </summary>
			public IntPtr ai_addr;

			/// <summary>
			/// A pointer to data that is used to return provider-specific namespace information that is associated with the name beyond a
			/// list of addresses. The length, in bytes, of the buffer pointed to by <c>ai_blob</c> must be specified in the
			/// <c>ai_bloblen</c> member.
			/// </summary>
			public IntPtr ai_blob;

			/// <summary>The length, in bytes, of the <c>ai_blob</c> member.</summary>
			public SizeT ai_bloblen;

			/// <summary>A pointer to the GUID of a specific namespace provider.</summary>
			public GuidPtr ai_provider;

			/// <summary>
			/// A pointer to the next structure in a linked list. This parameter is set to <c>NULL</c> in the last <c>addrinfoex2</c>
			/// structure of a linked list.
			/// </summary>
			public IntPtr ai_next;

			/// <summary>The version number of this structure. The value currently used for this version of the structure is 2.</summary>
			public int ai_version;

			/// <summary>The fully qualified domain name for the host.</summary>
			public StrPtrUni ai_fqdn;

			/// <summary>
			/// <para>Type: <c>struct sockaddr*</c></para>
			/// <para>
			/// A pointer to a sockaddr structure. The <c>ai_addr</c> member in each returned ADDRINFOW structure points to a filled-in
			/// socket address structure. The length, in bytes, of each returned <c>ADDRINFOW</c> structure is specified in the
			/// <c>ai_addrlen</c> member.
			/// </para>
			/// </summary>
			public SOCKADDR addr => new SOCKADDR(ai_addr, false, ai_addrlen);

			/// <inheritdoc/>
			public override string ToString() => $"{ai_fqdn}::{ai_canonname}:{ai_flags},{ai_family},{ai_socktype},{ai_protocol},{addr}";
		}

		/// <summary>The <c>addrinfoex</c> structure is used by the GetAddrInfoEx function to hold host address information.</summary>
		/// <remarks>
		/// <para>
		/// The <c>addrinfoex</c> structure is used by the GetAddrInfoEx function to hold host address information. The <c>addrinfoex</c>
		/// structure is an enhanced version of the addrinfo and addrinfoW structures. The extra structure members are for blob data and the
		/// GUID for the namespace provider. The blob data is used to return additional provider-specific namespace information associated
		/// with a name. The format of data in the <c>ai_blob</c> member is specific to a particular namespace provider. Currently, blob
		/// data is used by the <c>NS_EMAIL</c> namespace provider to supply additional information.
		/// </para>
		/// <para>
		/// The <c>addrinfoex</c> structure is an enhanced version of the addrinfo and addrinfoW structure used with GetAddrInfoEx function.
		/// The <c>GetAddrInfoEx</c> function allows specifying the namespace provider to resolve the query. For use with the IPv6 and IPv4
		/// protocol, name resolution can be by the Domain Name System (DNS), a local hosts file, an email provider (the <c>NS_EMAIL</c>
		/// namespace), or by other naming mechanisms.
		/// </para>
		/// <para>
		/// When UNICODE or _UNICODE is defined, <c>addrinfoex</c> is defined to <c>addrinfoexW</c>, the Unicode version of this structure.
		/// The string parameters are defined to the <c>PWSTR</c> data type and the <c>addrinfoexW</c> structure is used.
		/// </para>
		/// <para>
		/// When UNICODE or _UNICODE is not defined, <c>addrinfoex</c> is defined to <c>addrinfoexA</c>, the ANSI version of this structure.
		/// The string parameters are of the <c>PCSTR</c> data type and the <c>addrinfoexA</c> structure is used.
		/// </para>
		/// <para>
		/// Upon a successful call to GetAddrInfoEx, a linked list of <c>addrinfoex</c> structures is returned in the ppResult parameter
		/// passed to the <c>GetAddrInfoEx</c> function. The list can be processed by following the pointer provided in the <c>ai_next</c>
		/// member of each returned <c>addrinfoex</c> structure until a <c>NULL</c> pointer is encountered. In each returned
		/// <c>addrinfoex</c> structure, the <c>ai_family</c>, <c>ai_socktype</c>, and <c>ai_protocol</c> members correspond to respective
		/// arguments in a socket or WSASocket function call. Also, the <c>ai_addr</c> member in each returned <c>addrinfoex</c> structure
		/// points to a filled-in socket address structure, the length of which is specified in its <c>ai_addrlen</c> member.
		/// </para>
		/// <para>Examples</para>
		/// <para>The following example demonstrates the use of the <c>addrinfoex</c> structure.</para>
		/// <para>
		/// <c>Note</c> Ensure that the development environment targets the newest version of Ws2tcpip.h which includes structure and
		/// function definitions for <c>ADDRINFOEX</c> and GetAddrInfoEx, respectively.
		/// </para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/ws2def/ns-ws2def-addrinfoexa typedef struct addrinfoexA { int ai_flags; int
		// ai_family; int ai_socktype; int ai_protocol; size_t ai_addrlen; char *ai_canonname; struct sockaddr *ai_addr; void *ai_blob;
		// size_t ai_bloblen; LPGUID ai_provider; struct addrinfoexA *ai_next; } ADDRINFOEXA, *PADDRINFOEXA, *LPADDRINFOEXA;
		[PInvokeData("ws2def.h", MSDNShortId = "1077e03d-a1a4-45ab-a5d2-29a67e03f5df")]
		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
		public unsafe struct ADDRINFOEXW
		{
			/// <summary>
			/// <para>Type: <c>int</c></para>
			/// <para>Flags that indicate options used in the GetAddrInfoEx function.</para>
			/// <para>
			/// Supported values for the <c>ai_flags</c> member are defined in the Winsock2.h include file and can be a combination of the
			/// following options.
			/// </para>
			/// <list type="table">
			/// <listheader>
			/// <term>Value</term>
			/// <term>Meaning</term>
			/// </listheader>
			/// <item>
			/// <term>AI_PASSIVE 0x01</term>
			/// <term>The socket address will be used in a call to the bindfunction.</term>
			/// </item>
			/// <item>
			/// <term>AI_CANONNAME 0x02</term>
			/// <term>
			/// The canonical name is returned in the first ai_canonname member. When both the AI_CANONNAME and AI_FQDN bits are set, an
			/// addrinfoex2 structure is returned not the addrinfoex structure.
			/// </term>
			/// </item>
			/// <item>
			/// <term>AI_NUMERICHOST 0x04</term>
			/// <term>The nodename parameter passed to the GetAddrInfoEx function must be a numeric string.</term>
			/// </item>
			/// <item>
			/// <term>AI_ALL 0x0100</term>
			/// <term>
			/// If this bit is set, a request is made for IPv6 addresses and IPv4 addresses with AI_V4MAPPED. This option is supported on
			/// Windows Vista and later.
			/// </term>
			/// </item>
			/// <item>
			/// <term>AI_ADDRCONFIG 0x0400</term>
			/// <term>
			/// The GetAddrInfoEx will resolve only if a global address is configured. The IPv6 and IPv4 loopback address is not considered
			/// a valid global address. This option is only supported on Windows Vista and later.
			/// </term>
			/// </item>
			/// <item>
			/// <term>AI_V4MAPPED 0x0800</term>
			/// <term>
			/// If the GetAddrInfoEx request for an IPv6 addresses fails, a name service request is made for IPv4 addresses and these
			/// addresses are converted to IPv4-mapped IPv6 address format. This option is supported on Windows Vista and later.
			/// </term>
			/// </item>
			/// <item>
			/// <term>AI_NON_AUTHORITATIVE 0x04000</term>
			/// <term>
			/// The address information is from non-authoritative results. When this option is set in the pHints parameter of GetAddrInfoEx,
			/// the NS_EMAIL namespace provider returns both authoritative and non-authoritative results. If this option is not set, then
			/// only authoritative results are returned. In the ppResults parameter returned by GetAddrInfoEx, this flag is set in the
			/// ai_flags member of the addrinfoex structure for non-authoritative results. This option is only supported on Windows Vista
			/// and later for the NS_EMAIL namespace.
			/// </term>
			/// </item>
			/// <item>
			/// <term>AI_SECURE 0x08000</term>
			/// <term>
			/// The address information is from a secure channel. If the AI_SECURE bit is set, the NS_EMAIL namespace provider will return
			/// results that were obtained with enhanced security to minimize possible spoofing. When this option is set in the pHints
			/// parameter of GetAddrInfoEx, the NS_EMAIL namespace provider returns only results that were obtained with enhanced security
			/// to minimize possible spoofing. In the ppResults parameter returned by GetAddrInfoEx, this flag is set in the ai_flags member
			/// of the addrinfoex structure for results returned with enhanced security to minimize possible spoofing. This option is only
			/// supported on Windows Vista and later for the NS_EMAIL namespace.
			/// </term>
			/// </item>
			/// <item>
			/// <term>AI_RETURN_PREFERRED_NAMES 0x010000</term>
			/// <term>
			/// The address information is for a preferred names for publication with a specific namespace. When this option is set in the
			/// pHints parameter of GetAddrInfoEx, no name should be provided in the pName parameter and the NS_EMAIL namespace provider
			/// will return preferred names for publication. In the ppResults parameter returned by GetAddrInfoEx, this flag is set in the
			/// ai_flags member of the addrinfoex structure for results returned for preferred names for publication. This option is only
			/// supported on Windows Vista and later for the NS_EMAIL namespace.
			/// </term>
			/// </item>
			/// <item>
			/// <term>AI_FQDN 0x00020000</term>
			/// <term>
			/// The fully qualified domain name is returned in the first ai_canonicalname member. When this option is set in the pHints
			/// parameter of GetAddrInfoEx and a flat name (single label) is specified in the pName parameter, the fully qualified domain
			/// name that the name eventually resolved to will be returned. When both the AI_CANONNAME and AI_FQDN bits are set, an
			/// addrinfoex2 structure is returned not the addrinfoex structure. This option is supported on Windows 7, Windows Server 2008
			/// R2, and later.
			/// </term>
			/// </item>
			/// <item>
			/// <term>AI_FILESERVER 0x00040000</term>
			/// <term>
			/// A hint to the namespace provider that the hostname being queried is being used in a file share scenario. The namespace
			/// provider may ignore this hint. This option is supported on Windows 7, Windows Server 2008 R2, and later.
			/// </term>
			/// </item>
			/// <item>
			/// <term>AI_DISABLE_IDN_ENCODING 0x00080000</term>
			/// <term>
			/// Disable the automatic International Domain Name encoding using Punycode in the name resolution functions called by the
			/// GetAddrInfoEx function. This option is supported on Windows 8, Windows Server 2012, and later.
			/// </term>
			/// </item>
			/// </list>
			/// </summary>
			public ADDRINFO_FLAGS ai_flags;

			private uint _ai_family;

			/// <summary>
			/// <para>Type: <c>int</c></para>
			/// <para>The address family. Possible values for the address family are defined in the Winsock2.h include file.</para>
			/// <para>
			/// On the Windows SDK released for Windows Vista and later,, the organization of header files has changed and the possible
			/// values for the address family are defined in the Ws2def.h header file. Note that the Ws2def.h header file is automatically
			/// included in Winsock2.h, and should never be used directly.
			/// </para>
			/// <para>
			/// The values currently supported are <c>AF_INET</c> or <c>AF_INET6</c>, which are the Internet address family formats for IPv4
			/// and IPv6. Other options for address family ( <c>AF_NETBIOS</c> for use with NetBIOS, for example) are supported if a Windows
			/// Sockets service provider for the address family is installed. Note that the values for the AF_ address family and PF_
			/// protocol family constants are identical (for example, <c>AF_UNSPEC</c> and <c>PF_UNSPEC</c>), so either constant can be used.
			/// </para>
			/// <para>The table below lists common values for the address family although many other values are possible.</para>
			/// <list type="table">
			/// <listheader>
			/// <term>Value</term>
			/// <term>Meaning</term>
			/// </listheader>
			/// <item>
			/// <term>AF_UNSPEC 0</term>
			/// <term>The address family is unspecified.</term>
			/// </item>
			/// <item>
			/// <term>AF_INET 2</term>
			/// <term>The Internet Protocol version 4 (IPv4) address family.</term>
			/// </item>
			/// <item>
			/// <term>AF_NETBIOS 17</term>
			/// <term>The NetBIOS address family. This address family is only supported if a Windows Sockets provider for NetBIOS is installed.</term>
			/// </item>
			/// <item>
			/// <term>AF_INET6 23</term>
			/// <term>The Internet Protocol version 6 (IPv6) address family.</term>
			/// </item>
			/// <item>
			/// <term>AF_IRDA 26</term>
			/// <term>
			/// The Infrared Data Association (IrDA) address family. This address family is only supported if the computer has an infrared
			/// port and driver installed.
			/// </term>
			/// </item>
			/// <item>
			/// <term>AF_BTH 32</term>
			/// <term>
			/// The Bluetooth address family. This address family is only supported if a Bluetooth adapter is installed on Windows Server
			/// 2003 or later.
			/// </term>
			/// </item>
			/// </list>
			/// </summary>
			public ADDRESS_FAMILY ai_family { get => (ADDRESS_FAMILY)_ai_family; set => _ai_family = (ushort)value; }

			/// <summary>
			/// <para>Type: <c>int</c></para>
			/// <para>The socket type. Possible values for the socket type are defined in the Winsock2.h include file.</para>
			/// <para>The following table lists the possible values for the socket type supported for Windows Sockets 2:</para>
			/// <list type="table">
			/// <listheader>
			/// <term>Value</term>
			/// <term>Meaning</term>
			/// </listheader>
			/// <item>
			/// <term>SOCK_STREAM 1</term>
			/// <term>
			/// Provides sequenced, reliable, two-way, connection-based byte streams with an OOB data transmission mechanism. Uses the
			/// Transmission Control Protocol (TCP) for the Internet address family (AF_INET or AF_INET6). If the ai_family member is
			/// AF_IRDA, then SOCK_STREAM is the only supported socket type.
			/// </term>
			/// </item>
			/// <item>
			/// <term>SOCK_DGRAM 2</term>
			/// <term>
			/// Supports datagrams, which are connectionless, unreliable buffers of a fixed (typically small) maximum length. Uses the User
			/// Datagram Protocol (UDP) for the Internet address family (AF_INET or AF_INET6).
			/// </term>
			/// </item>
			/// <item>
			/// <term>SOCK_RAW 3</term>
			/// <term>
			/// Provides a raw socket that allows an application to manipulate the next upper-layer protocol header. To manipulate the IPv4
			/// header, the IP_HDRINCL socket option must be set on the socket. To manipulate the IPv6 header, the IPV6_HDRINCL socket
			/// option must be set on the socket.
			/// </term>
			/// </item>
			/// <item>
			/// <term>SOCK_RDM 4</term>
			/// <term>
			/// Provides a reliable message datagram. An example of this type is the Pragmatic General Multicast (PGM) multicast protocol
			/// implementation in Windows, often referred to as reliable multicast programming.
			/// </term>
			/// </item>
			/// <item>
			/// <term>SOCK_SEQPACKET 5</term>
			/// <term>Provides a pseudo-stream packet based on datagrams.</term>
			/// </item>
			/// </list>
			/// <para>
			/// In Windows Sockets 2, new socket types were introduced. An application can dynamically discover the attributes of each
			/// available transport protocol through the WSAEnumProtocols function. So an application can determine the possible socket type
			/// and protocol options for an address family and use this information when specifying this parameter. Socket type definitions
			/// in the Winsock2.h and Ws2def.h header files will be periodically updated as new socket types, address families, and
			/// protocols are defined.
			/// </para>
			/// <para>In Windows Sockets 1.1, the only possible socket types are <c>SOCK_DATAGRAM</c> and <c>SOCK_STREAM</c>.</para>
			/// </summary>
			public SOCK ai_socktype;

			/// <summary>
			/// <para>Type: <c>int</c></para>
			/// <para>
			/// The protocol type. The possible options are specific to the address family and socket type specified. Possible values for
			/// the <c>ai_protocol</c> are defined in Winsock2.h and the Wsrm.h header files.
			/// </para>
			/// <para>
			/// On the Windows SDK released for Windows Vista and later,, the organization of header files has changed and this member can
			/// be one of the values from the <c>IPPROTO</c> enumeration type defined in the Ws2def.h header file. Note that the Ws2def.h
			/// header file is automatically included in Winsock2.h, and should never be used directly.
			/// </para>
			/// <para>
			/// If a value of 0 is specified for <c>ai_protocol</c>, the caller does not wish to specify a protocol and the service provider
			/// will choose the <c>ai_protocol</c> to use. For protocols other than IPv4 and IPv6, set <c>ai_protocol</c> to zero.
			/// </para>
			/// <para>The following table lists common values for the <c>ai_protocol</c> member although many other values are possible.</para>
			/// <list type="table">
			/// <listheader>
			/// <term>Value</term>
			/// <term>Meaning</term>
			/// </listheader>
			/// <item>
			/// <term>IPPROTO_TCP 6</term>
			/// <term>
			/// The Transmission Control Protocol (TCP). This is a possible value when the ai_family member is AF_INET or AF_INET6 and the
			/// ai_socktype member is SOCK_STREAM.
			/// </term>
			/// </item>
			/// <item>
			/// <term>IPPROTO_UDP 17</term>
			/// <term>
			/// The User Datagram Protocol (UDP). This is a possible value when the ai_family member is AF_INET or AF_INET6 and the type
			/// parameter is SOCK_DGRAM.
			/// </term>
			/// </item>
			/// <item>
			/// <term>IPPROTO_RM 113</term>
			/// <term>
			/// The PGM protocol for reliable multicast. This is a possible value when the ai_family member is AF_INET and the ai_socktype
			/// member is SOCK_RDM. On the Windows SDK released for Windows Vista and later, this value is also called IPPROTO_PGM.
			/// </term>
			/// </item>
			/// </list>
			/// <para>If the <c>ai_family</c> member is <c>AF_IRDA</c>, then the <c>ai_protocol</c> must be 0.</para>
			/// </summary>
			public IPPROTO ai_protocol;

			/// <summary>
			/// <para>Type: <c>size_t</c></para>
			/// <para>The length, in bytes, of the buffer pointed to by the <c>ai_addr</c> member.</para>
			/// </summary>
			public SizeT ai_addrlen;

			/// <summary>
			/// <para>Type: <c>PCTSTR</c></para>
			/// <para>The canonical name for the host.</para>
			/// </summary>
			public StrPtrUni ai_canonname;

			/// <summary>
			/// <para>Type: <c>struct sockaddr*</c></para>
			/// <para>
			/// A pointer to a sockaddr structure. The <c>ai_addr</c> member in each returned <c>addrinfoex</c> structure points to a
			/// filled-in socket address structure. The length, in bytes, of each returned <c>addrinfoex</c> structure is specified in the
			/// <c>ai_addrlen</c> member.
			/// </para>
			/// </summary>
			public IntPtr ai_addr;

			/// <summary>
			/// <para>Type: <c>void*</c></para>
			/// <para>
			/// A pointer to data that is used to return provider-specific namespace information that is associated with the name beyond a
			/// list of addresses. The length, in bytes, of the buffer pointed to by <c>ai_blob</c> must be specified in the
			/// <c>ai_bloblen</c> member.
			/// </para>
			/// </summary>
			public IntPtr ai_blob;

			/// <summary>
			/// <para>Type: <c>size_t</c></para>
			/// <para>The length, in bytes, of the <c>ai_blob</c> member.</para>
			/// </summary>
			public SizeT ai_bloblen;

			/// <summary>
			/// <para>Type: <c>LPGUID</c></para>
			/// <para>A pointer to the GUID of a specific namespace provider.</para>
			/// </summary>
			public Guid* ai_provider;

			/// <summary>
			/// <para>Type: <c>struct addrinfoex*</c></para>
			/// <para>
			/// A pointer to the next structure in a linked list. This parameter is set to <c>NULL</c> in the last <c>addrinfoex</c>
			/// structure of a linked list.
			/// </para>
			/// </summary>
			public IntPtr ai_next;

			/// <summary>
			/// <para>Type: <c>struct sockaddr*</c></para>
			/// <para>
			/// A pointer to a sockaddr structure. The <c>ai_addr</c> member in each returned ADDRINFOW structure points to a filled-in
			/// socket address structure. The length, in bytes, of each returned <c>ADDRINFOW</c> structure is specified in the
			/// <c>ai_addrlen</c> member.
			/// </para>
			/// </summary>
			public SOCKADDR addr => new SOCKADDR(ai_addr, false, ai_addrlen);

			/// <inheritdoc/>
			public override string ToString() => $"{ai_canonname}:{ai_flags},{ai_family},{ai_socktype},{ai_protocol},{addr}";
		}

		/// <summary>
		/// The <c>addrinfoex2</c> structure is used by the GetAddrInfoEx function to hold host address information when both a canonical
		/// name and a fully qualified domain name have been requested.
		/// </summary>
		/// <remarks>
		/// <para>The <c>addrinfoex2</c> structure is supported on Windows 8 and Windows Server 2012</para>
		/// <para>
		/// The <c>addrinfoex2</c> structure is used by the GetAddrInfoEx function to hold host address information when both the
		/// <c>AI_FQDN</c> and <c>AI_CANONNAME</c> bits are set in the <c>ai_flags</c> member of the optional addrinfoex structure provided
		/// in the hints parameter to the <c>GetAddrInfoEx</c> function. The <c>addrinfoex2</c> structure is an enhanced version of the
		/// <c>addrinfoex</c> structure that can return both the canonical name and the fully qualified domain name for the host. The extra
		/// structure members are for a version number of the structure and the fully qualified domain name for the host.
		/// </para>
		/// <para>
		/// The <c>addrinfoex2</c> structure used with GetAddrInfoEx function is an enhanced version of the addrinfo and addrinfoW
		/// structures used with the getaddrinfo and GetAddrInfoW functions. The <c>GetAddrInfoEx</c> function allows specifying the
		/// namespace provider to resolve the query. For use with the IPv6 and IPv4 protocol, name resolution can be by the Domain Name
		/// System (DNS), a local hosts file, an email provider (the <c>NS_EMAIL</c> namespace), or by other naming mechanisms.
		/// </para>
		/// <para>
		/// The blob data in tha <c>ai_blob</c> member is used to return additional provider-specific namespace information associated with
		/// a name. The format of data in the <c>ai_blob</c> member is specific to a particular namespace provider. Currently, blob data is
		/// used by the <c>NS_EMAIL</c> namespace provider to supply additional information.
		/// </para>
		/// <para>
		/// When UNICODE or _UNICODE is defined, <c>addrinfoex2</c> is defined to <c>addrinfoex2W</c>, the Unicode version of this
		/// structure. The string parameters are defined to the <c>PWSTR</c> data type and the <c>addrinfoex2W</c> structure is used.
		/// </para>
		/// <para>
		/// When UNICODE or _UNICODE is not defined, <c>addrinfoex2</c> is defined to <c>addrinfoex2A</c>, the ANSI version of this
		/// structure. The string parameters are of the <c>char *</c> data type and the <c>addrinfoex2A</c> structure is used.
		/// </para>
		/// <para>
		/// Upon a successful call to GetAddrInfoEx, a linked list of <c>addrinfoex2</c> structures is returned in the ppResult parameter
		/// passed to the <c>GetAddrInfoEx</c> function. The list can be processed by following the pointer provided in the <c>ai_next</c>
		/// member of each returned <c>addrinfoex2</c> structure until a <c>NULL</c> pointer is encountered. In each returned
		/// <c>addrinfoex2</c> structure, the <c>ai_family</c>, <c>ai_socktype</c>, and <c>ai_protocol</c> members correspond to respective
		/// arguments in a socket or WSASocket function call. Also, the <c>ai_addr</c> member in each returned <c>addrinfoex2</c> structure
		/// points to a filled-in socket address structure, the length of which is specified in its <c>ai_addrlen</c> member.
		/// </para>
		/// </remarks>
		/// <summary>The <c>addrinfo</c> structure is used by the getaddrinfo function to hold host address information.</summary>
		/// <remarks>
		/// <para>The <c>addrinfo</c> structure is used by the ANSI getaddrinfo function to hold host address information.</para>
		/// <para>The addrinfoW structure is the version of this structure used by the Unicode GetAddrInfoW function.</para>
		/// <para>
		/// Macros in the Ws2tcpip.h header file define a <c>ADDRINFOT</c> structure and a mixed-case function name of <c>GetAddrInfo</c>.
		/// The <c>GetAddrInfo</c> function should be called with the nodename and servname parameters of a pointer of type <c>TCHAR</c> and
		/// the hints and res parameters of a pointer of type <c>ADDRINFOT</c>. When UNICODE or _UNICODE is not defined, <c>ADDRINFOT</c> is
		/// defined to the <c>addrinfo</c> structure and <c>GetAddrInfo</c> is defined to getaddrinfo, the ANSI version of this function.
		/// When UNICODE or _UNICODE is defined, <c>ADDRINFOT</c> is defined to the addrinfoW structure and <c>GetAddrInfo</c> is defined to
		/// GetAddrInfoW, the Unicode version of this function.
		/// </para>
		/// <para>
		/// Upon a successful call to getaddrinfo, a linked list of <c>addrinfo</c> structures is returned in the res parameter passed to
		/// the <c>getaddrinfo</c> function. The list can be processed by following the pointer provided in the <c>ai_next</c> member of
		/// each returned <c>addrinfo</c> structure until a <c>NULL</c> pointer is encountered. In each returned <c>addrinfo</c> structure,
		/// the <c>ai_family</c>, <c>ai_socktype</c>, and <c>ai_protocol</c> members correspond to respective arguments in a socket or
		/// WSASocket function call. Also, the <c>ai_addr</c> member in each returned <c>addrinfo</c> structure points to a filled-in socket
		/// address structure, the length of which is specified in its <c>ai_addrlen</c> member.
		/// </para>
		/// <para>Support for getaddrinfo and the addrinfo struct on older versions of Windows</para>
		/// <para>
		/// The getaddrinfo function that uses the <c>addrinfo</c> structure was added to the Ws2_32.dll on Windows XP and later. The
		/// <c>addrinfo</c> structure is defined in the Ws2tcpip.h header file included with the Platform SDK released for Windows XP and
		/// later and the Windows SDK released for Windows Vista and later.
		/// </para>
		/// <para>
		/// To execute an application that uses the getaddrinfo function and the <c>addrinfo</c> structure on earlier versions of Windows
		/// (Windows 2000), then you need to include the Ws2tcpip.h and Wspiapi.h files. When the Wspiapi.h include file is added, the
		/// <c>getaddrinfo</c> function is defined to the WspiapiGetAddrInfo inline function in the Wspiapi.h file. At runtime, the
		/// WspiapiGetAddrInfo function is implemented in such a way that if the Ws2_32.dll or the Wship6.dll (the file containing
		/// <c>getaddrinfo</c> in the IPv6 Technology Preview for Windows 2000) does not include <c>getaddrinfo</c>, then a version of
		/// <c>getaddrinfo</c> is implemented inline based on code in the Wspiapi.h header file. This inline code will be used on older
		/// Windows platforms that do not natively support the <c>getaddrinfo</c> function.
		/// </para>
		/// <para>
		/// The IPv6 protocol is supported on Windows 2000 when the IPv6 Technology Preview for Windows 2000 is installed. Otherwise
		/// getaddrinfo support on versions of Windows earlier than Windows XP is limited to handling IPv4 name resolution.
		/// </para>
		/// <para>
		/// The GetAddrInfoW function that uses the addrinfoW structure is the Unicode version of the getaddrinfo function and associated
		/// <c>addrinfo</c> structure. The <c>GetAddrInfoW</c> function was added to the Ws2_32.dll in Windows XP with Service Pack 2 (SP2).
		/// The <c>GetAddrInfoW</c> function and the <c>addrinfoW</c> structure cannot be used on versions of Windows earlier than Windows
		/// XP with SP2.
		/// </para>
		/// <para>Examples</para>
		/// <para>The following code example shows the use of the <c>addrinfo</c> structure.</para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/ws2def/ns-ws2def-addrinfoa typedef struct addrinfo { int ai_flags; int
		// ai_family; int ai_socktype; int ai_protocol; size_t ai_addrlen; char *ai_canonname; struct sockaddr *ai_addr; struct addrinfo
		// *ai_next; } ADDRINFOA, *PADDRINFOA;
		[PInvokeData("ws2def.h", MSDNShortId = "4df914ab-59b0-4110-bc81-59e5f6722b8d")]
		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
		public struct ADDRINFOW
		{
			/// <summary>
			/// <para>Type: <c>int</c></para>
			/// <para>Flags that indicate options used in the getaddrinfo function.</para>
			/// <para>
			/// Supported values for the <c>ai_flags</c> member are defined in the Ws2def.h header file on the Windows SDK for Windows 7 and
			/// later. These values are defined in the Ws2tcpip.h header file on the Windows SDK for Windows Server 2008 and Windows Vista.
			/// These values are defined in the Ws2tcpip.h header file on the Platform SDK for Windows Server 2003, and Windows XP.
			/// Supported values for the <c>ai_flags</c> member can be a combination of the following options.
			/// </para>
			/// <list type="table">
			/// <listheader>
			/// <term>Value</term>
			/// <term>Meaning</term>
			/// </listheader>
			/// <item>
			/// <term>AI_PASSIVE 0x01</term>
			/// <term>The socket address will be used in a call to the bindfunction.</term>
			/// </item>
			/// <item>
			/// <term>AI_CANONNAME 0x02</term>
			/// <term>The canonical name is returned in the first ai_canonname member.</term>
			/// </item>
			/// <item>
			/// <term>AI_NUMERICHOST 0x04</term>
			/// <term>The nodename parameter passed to the getaddrinfo function must be a numeric string.</term>
			/// </item>
			/// <item>
			/// <term>AI_ALL 0x0100</term>
			/// <term>
			/// If this bit is set, a request is made for IPv6 addresses and IPv4 addresses with AI_V4MAPPED. This option is supported on
			/// Windows Vista and later.
			/// </term>
			/// </item>
			/// <item>
			/// <term>AI_ADDRCONFIG 0x0400</term>
			/// <term>
			/// The getaddrinfo will resolve only if a global address is configured. The IPv6 and IPv4 loopback address is not considered a
			/// valid global address. This option is supported on Windows Vista and later.
			/// </term>
			/// </item>
			/// <item>
			/// <term>AI_V4MAPPED 0x0800</term>
			/// <term>
			/// If the getaddrinfo request for IPv6 addresses fails, a name service request is made for IPv4 addresses and these addresses
			/// are converted to IPv4-mapped IPv6 address format. This option is supported on Windows Vista and later.
			/// </term>
			/// </item>
			/// <item>
			/// <term>AI_NON_AUTHORITATIVE 0x04000</term>
			/// <term>
			/// The address information can be from a non-authoritative namespace provider. This option is only supported on Windows Vista
			/// and later for the NS_EMAIL namespace.
			/// </term>
			/// </item>
			/// <item>
			/// <term>AI_SECURE 0x08000</term>
			/// <term>
			/// The address information is from a secure channel. This option is only supported on Windows Vista and later for the NS_EMAIL namespace.
			/// </term>
			/// </item>
			/// <item>
			/// <term>AI_RETURN_PREFERRED_NAMES 0x010000</term>
			/// <term>
			/// The address information is for a preferred name for a user. This option is only supported on Windows Vista and later for the
			/// NS_EMAIL namespace.
			/// </term>
			/// </item>
			/// <item>
			/// <term>AI_FQDN 0x00020000</term>
			/// <term>
			/// If a flat name (single label) is specified, getaddrinfo will return the fully qualified domain name that the name eventually
			/// resolved to. The fully qualified domain name is returned in the ai_canonname member. This is different than AI_CANONNAME bit
			/// flag that returns the canonical name registered in DNS which may be different than the fully qualified domain name that the
			/// flat name resolved to. Only one of the AI_FQDN and AI_CANONNAME bits can be set. The getaddrinfo function will fail if both
			/// flags are present with EAI_BADFLAGS. This option is supported on Windows 7, Windows Server 2008 R2, and later.
			/// </term>
			/// </item>
			/// <item>
			/// <term>AI_FILESERVER 0x00040000</term>
			/// <term>
			/// A hint to the namespace provider that the hostname being queried is being used in a file share scenario. The namespace
			/// provider may ignore this hint. This option is supported on Windows 7, Windows Server 2008 R2, and later.
			/// </term>
			/// </item>
			/// </list>
			/// </summary>
			public ADDRINFO_FLAGS ai_flags;

			private uint _ai_family;

			/// <summary>
			/// <para>Type: <c>int</c></para>
			/// <para>The address family. Possible values for the address family are defined in the Winsock2.h include file.</para>
			/// <para>
			/// On the Windows SDK released for Windows Vista and later,, the organization of header files has changed and the possible
			/// values for the address family are defined in the Ws2def.h header file. Note that the Ws2def.h header file is automatically
			/// included in Winsock2.h, and should never be used directly.
			/// </para>
			/// <para>
			/// The values currently supported are <c>AF_INET</c> or <c>AF_INET6</c>, which are the Internet address family formats for IPv4
			/// and IPv6. Other options for address family ( <c>AF_NETBIOS</c> for use with NetBIOS, for example) are supported if a Windows
			/// Sockets service provider for the address family is installed. Note that the values for the AF_ address family and PF_
			/// protocol family constants are identical (for example, <c>AF_UNSPEC</c> and <c>PF_UNSPEC</c>), so either constant can be used.
			/// </para>
			/// <para>The table below lists common values for the address family although many other values are possible.</para>
			/// <list type="table">
			/// <listheader>
			/// <term>Value</term>
			/// <term>Meaning</term>
			/// </listheader>
			/// <item>
			/// <term>AF_UNSPEC 0</term>
			/// <term>The address family is unspecified.</term>
			/// </item>
			/// <item>
			/// <term>AF_INET 2</term>
			/// <term>The Internet Protocol version 4 (IPv4) address family.</term>
			/// </item>
			/// <item>
			/// <term>AF_NETBIOS 17</term>
			/// <term>The NetBIOS address family. This address family is only supported if a Windows Sockets provider for NetBIOS is installed.</term>
			/// </item>
			/// <item>
			/// <term>AF_INET6 23</term>
			/// <term>The Internet Protocol version 6 (IPv6) address family.</term>
			/// </item>
			/// <item>
			/// <term>AF_IRDA 26</term>
			/// <term>
			/// The Infrared Data Association (IrDA) address family. This address family is only supported if the computer has an infrared
			/// port and driver installed.
			/// </term>
			/// </item>
			/// <item>
			/// <term>AF_BTH 32</term>
			/// <term>
			/// The Bluetooth address family. This address family is only supported if a Bluetooth adapter is installed on Windows Server
			/// 2003 or later.
			/// </term>
			/// </item>
			/// </list>
			/// </summary>
			public ADDRESS_FAMILY ai_family { get => (ADDRESS_FAMILY)_ai_family; set => _ai_family = (ushort)value; }

			/// <summary>
			/// <para>Type: <c>int</c></para>
			/// <para>The socket type. Possible values for the socket type are defined in the Winsock2.h header file.</para>
			/// <para>The following table lists the possible values for the socket type supported for Windows Sockets 2:</para>
			/// <list type="table">
			/// <listheader>
			/// <term>Value</term>
			/// <term>Meaning</term>
			/// </listheader>
			/// <item>
			/// <term>SOCK_STREAM 1</term>
			/// <term>
			/// Provides sequenced, reliable, two-way, connection-based byte streams with an OOB data transmission mechanism. Uses the
			/// Transmission Control Protocol (TCP) for the Internet address family (AF_INET or AF_INET6). If the ai_family member is
			/// AF_IRDA, then SOCK_STREAM is the only supported socket type.
			/// </term>
			/// </item>
			/// <item>
			/// <term>SOCK_DGRAM 2</term>
			/// <term>
			/// Supports datagrams, which are connectionless, unreliable buffers of a fixed (typically small) maximum length. Uses the User
			/// Datagram Protocol (UDP) for the Internet address family (AF_INET or AF_INET6).
			/// </term>
			/// </item>
			/// <item>
			/// <term>SOCK_RAW 3</term>
			/// <term>
			/// Provides a raw socket that allows an application to manipulate the next upper-layer protocol header. To manipulate the IPv4
			/// header, the IP_HDRINCL socket option must be set on the socket. To manipulate the IPv6 header, the IPV6_HDRINCL socket
			/// option must be set on the socket.
			/// </term>
			/// </item>
			/// <item>
			/// <term>SOCK_RDM 4</term>
			/// <term>
			/// Provides a reliable message datagram. An example of this type is the Pragmatic General Multicast (PGM) multicast protocol
			/// implementation in Windows, often referred to as reliable multicast programming.
			/// </term>
			/// </item>
			/// <item>
			/// <term>SOCK_SEQPACKET 5</term>
			/// <term>Provides a pseudo-stream packet based on datagrams.</term>
			/// </item>
			/// </list>
			/// <para>
			/// In Windows Sockets 2, new socket types were introduced. An application can dynamically discover the attributes of each
			/// available transport protocol through the WSAEnumProtocols function. So an application can determine the possible socket type
			/// and protocol options for an address family and use this information when specifying this parameter. Socket type definitions
			/// in the Winsock2.h and Ws2def.h header files will be periodically updated as new socket types, address families, and
			/// protocols are defined.
			/// </para>
			/// <para>In Windows Sockets 1.1, the only possible socket types are <c>SOCK_DATAGRAM</c> and <c>SOCK_STREAM</c>.</para>
			/// </summary>
			public SOCK ai_socktype;

			/// <summary>
			/// <para>Type: <c>int</c></para>
			/// <para>
			/// The protocol type. The possible options are specific to the address family and socket type specified. Possible values for
			/// the <c>ai_protocol</c> are defined in the Winsock2.h and Wsrm.h header files.
			/// </para>
			/// <para>
			/// On the Windows SDK released for Windows Vista and later, the organization of header files has changed and this member can be
			/// one of the values from the <c>IPPROTO</c> enumeration type defined in the Ws2def.h header file. Note that the Ws2def.h
			/// header file is automatically included in Winsock2.h, and should never be used directly.
			/// </para>
			/// <para>
			/// If a value of 0 is specified for <c>ai_protocol</c>, the caller does not wish to specify a protocol and the service provider
			/// will choose the <c>ai_protocol</c> to use. For protocols other than IPv4 and IPv6, set <c>ai_protocol</c> to zero.
			/// </para>
			/// <para>The following table lists common values for the <c>ai_protocol</c> member although many other values are possible.</para>
			/// <list type="table">
			/// <listheader>
			/// <term>Value</term>
			/// <term>Meaning</term>
			/// </listheader>
			/// <item>
			/// <term>IPPROTO_TCP 6</term>
			/// <term>
			/// The Transmission Control Protocol (TCP). This is a possible value when the ai_family member is AF_INET or AF_INET6 and the
			/// ai_socktype member is SOCK_STREAM.
			/// </term>
			/// </item>
			/// <item>
			/// <term>IPPROTO_UDP 17</term>
			/// <term>
			/// The User Datagram Protocol (UDP). This is a possible value when the ai_family member is AF_INET or AF_INET6 and the type
			/// parameter is SOCK_DGRAM.
			/// </term>
			/// </item>
			/// <item>
			/// <term>IPPROTO_RM 113</term>
			/// <term>
			/// The PGM protocol for reliable multicast. This is a possible value when the ai_family member is AF_INET and the ai_socktype
			/// member is SOCK_RDM. On the Windows SDK released for Windows Vista and later, this value is also called IPPROTO_PGM.
			/// </term>
			/// </item>
			/// </list>
			/// <para>If the <c>ai_family</c> member is <c>AF_IRDA</c>, then the <c>ai_protocol</c> must be 0.</para>
			/// </summary>
			public IPPROTO ai_protocol;

			/// <summary>
			/// <para>Type: <c>size_t</c></para>
			/// <para>The length, in bytes, of the buffer pointed to by the <c>ai_addr</c> member.</para>
			/// </summary>
			public SizeT ai_addrlen;

			/// <summary>
			/// <para>Type: <c>char*</c></para>
			/// <para>The canonical name for the host.</para>
			/// </summary>
			public StrPtrUni ai_canonname;

			/// <summary>
			/// <para>Type: <c>struct sockaddr*</c></para>
			/// <para>
			/// A pointer to a sockaddr structure. The <c>ai_addr</c> member in each returned <c>addrinfo</c> structure points to a
			/// filled-in socket address structure. The length, in bytes, of each returned <c>addrinfo</c> structure is specified in the
			/// <c>ai_addrlen</c> member.
			/// </para>
			/// </summary>
			public IntPtr ai_addr;

			/// <summary>
			/// <para>Type: <c>struct addrinfo*</c></para>
			/// <para>
			/// A pointer to the next structure in a linked list. This parameter is set to <c>NULL</c> in the last <c>addrinfo</c> structure
			/// of a linked list.
			/// </para>
			/// </summary>
			public IntPtr ai_next;

			/// <summary>
			/// <para>Type: <c>struct sockaddr*</c></para>
			/// <para>
			/// A pointer to a sockaddr structure. The <c>ai_addr</c> member in each returned ADDRINFOW structure points to a filled-in
			/// socket address structure. The length, in bytes, of each returned <c>ADDRINFOW</c> structure is specified in the
			/// <c>ai_addrlen</c> member.
			/// </para>
			/// </summary>
			public SOCKADDR addr => new SOCKADDR(ai_addr, false, ai_addrlen);

			/// <inheritdoc/>
			public override string ToString() => $"{ai_canonname}:{ai_flags},{ai_family},{ai_socktype},{ai_protocol},{addr}";
		}

		/// <summary>The scope identifier for the IPv6 transport address.</summary>
		[PInvokeData("ws2def.h")]
		[StructLayout(LayoutKind.Sequential)]
		public struct SCOPE_ID
		{
			/// <summary>A ULONG representation of the IPv6 scope identifier.</summary>
			public uint Value;

			/// <summary>
			/// <para>
			/// The zone index that identifies the zone to which the transport address pertains. Zones of the different scopes are
			/// instantiated as follows:
			/// </para>
			/// <list type="bullet">
			/// <item>Each interface on a node comprises a single zone of interface-local scope.</item>
			/// <item>Each link, and the interfaces attached to that link, comprise a single zone of link-local scope.</item>
			/// <item>There is a single zone of global scope that comprises all of the links and interfaces in the Internet.</item>
			/// <item>The boundaries of zones of scope other than interface-local, link-local, and global are defined by network administrators.</item>
			/// </list>
			/// <para>A value of zero specifies the default zone.</para>
			/// </summary>
			/// <value>The zone index.</value>
			public uint Zone
			{
				get => BitHelper.GetBits(Value, 0, 28);
				set => BitHelper.SetBits(ref Value, 0, 28, value);
			}

			/// <summary>
			/// <para>
			/// The scope of the IPv6 transport address. This scope must be the same as the IPv6 scope value that is embedded in the IPv6
			/// transport address. This member can be one of the following:
			/// </para>
			/// <para><strong>ScopeLevelInterface</strong></para>
			/// <para>The transport address has interface-local scope.</para>
			/// <para><strong>ScopeLevelLink</strong></para>
			/// <para>The transport address has link-local scope.</para>
			/// <para><strong>ScopeLevelSubnet</strong></para>
			/// <para>The transport address has subnet-local scope.</para>
			/// <para><strong>ScopeLevelAdmin</strong></para>
			/// <para>The transport address has admin-local scope.</para>
			/// <para><strong>ScopeLevelSite</strong></para>
			/// <para>The transport address has site-local scope.</para>
			/// <para><strong>ScopeLevelOrganization</strong></para>
			/// <para>The transport address has organization-local scope.</para>
			/// <para><strong>ScopeLevelGlobal</strong></para>
			/// <para>The transport address has global scope.</para>
			/// </summary>
			/// <value>The level.</value>
			public byte Level
			{
				get => (byte)BitHelper.GetBits(Value, 28, 4);
				set => BitHelper.SetBits(ref Value, 28, 4, value);
			}
		}

		/// <summary>The SOCKADDR_IN structure specifies a transport address and port for the AF_INET address family.</summary>
		/// <remarks>
		/// All of the data in the SOCKADDR_IN structure, except for the address family, must be specified in network-byte-order (big-endian).
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/ws2def/ns-ws2def-sockaddr_in typedef struct sockaddr_in { #if ... short
		// sin_family; #else ADDRESS_FAMILY sin_family; #endif USHORT sin_port; IN_ADDR sin_addr; CHAR sin_zero[8]; } SOCKADDR_IN, *PSOCKADDR_IN;
		[PInvokeData("ws2def.h", MSDNShortId = "96379562-403f-451c-ac7a-f0eec34bfe5e")]
		[StructLayout(LayoutKind.Sequential, Pack = 2)]
		public struct SOCKADDR_IN
		{
			/// <summary>The address family for the transport address. This member should always be set to AF_INET.</summary>
			public ADDRESS_FAMILY sin_family;

			/// <summary>A transport protocol port number.</summary>
			public ushort sin_port;

			/// <summary>An IN_ADDR structure that contains an IPv4 transport address.</summary>
			public IN_ADDR sin_addr;

			/// <summary>Reserved for system use. A WSK application should set the contents of this array to zero.</summary>
			public ulong sin_zero;

			/// <summary>Initializes a new instance of the <see cref="SOCKADDR_IN"/> struct.</summary>
			/// <param name="addr">An IN_ADDR structure that contains an IPv4 transport address.</param>
			/// <param name="port">A transport protocol port number.</param>
			public SOCKADDR_IN(IN_ADDR addr, ushort port = 0)
			{
				sin_family = ADDRESS_FAMILY.AF_INET;
				sin_port = port;
				sin_addr = addr;
				sin_zero = 0;
			}

			/// <summary>Performs an implicit conversion from <see cref="IN_ADDR"/> to <see cref="SOCKADDR_IN"/>.</summary>
			/// <param name="addr">The addr.</param>
			/// <returns>The resulting <see cref="SOCKADDR_IN"/> instance from the conversion.</returns>
			public static implicit operator SOCKADDR_IN(IN_ADDR addr) => new SOCKADDR_IN(addr);

			/// <summary>Converts to string.</summary>
			/// <returns>A <see cref="System.String"/> that represents this instance.</returns>
			public override string ToString() => $"{sin_addr}:{sin_port}";
		}

		/// <summary>The SOCKADDR_STORAGE structure is a generic structure that specifies a transport address.</summary>
		/// <remarks>
		/// A WSK application typically does not directly access any of the members of the SOCKADDR_STORAGE structure except for the
		/// <c>ss_family</c> member. Instead, a pointer to a SOCKADDR_STORAGE structure is normally cast to a pointer to the specific
		/// SOCKADDR structure type that corresponds to a particular address family.
		/// </remarks>
		// https://docs.microsoft.com/ja-jp/windows/desktop/api/ws2def/ns-ws2def-sockaddr_storage_lh typedef struct sockaddr_storage {
		// ADDRESS_FAMILY ss_family; CHAR __ss_pad1[_SS_PAD1SIZE]; __int64 __ss_align; CHAR __ss_pad2[_SS_PAD2SIZE]; } SOCKADDR_STORAGE_LH,
		// *PSOCKADDR_STORAGE_LH, *LPSOCKADDR_STORAGE_LH;
		[PInvokeData("ws2def.h", MSDNShortId = "27e56c1a-ce11-4cdb-9be8-25ed2f94fb37")]
		[StructLayout(LayoutKind.Sequential, Pack = 8)]
		public struct SOCKADDR_STORAGE
		{
			/// <summary>
			/// The address family for the transport address. For more information about supported address families, see WSK Address Families.
			/// </summary>
			public ADDRESS_FAMILY ss_family;

			/// <summary>A padding of 6 bytes that puts the <c>__ss_align</c> member on an eight-byte boundary within the structure.</summary>
			[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
			public byte[] __ss_pad1;

			/// <summary>A 64-bit value that forces the structure to be 8-byte aligned.</summary>
			public long __ss_align;

			/// <summary>A padding of an additional 112 bytes that brings the total size of the SOCKADDR_STORAGE structure to 128 bytes.</summary>
			[MarshalAs(UnmanagedType.ByValArray, SizeConst = 112)]
			public byte[] __ss_pad2;

			/// <summary>Performs an explicit conversion from <see cref="SOCKADDR_IN6"/> to <see cref="SOCKADDR_STORAGE"/>.</summary>
			/// <param name="addr">The address.</param>
			/// <returns>The resulting <see cref="SOCKADDR_STORAGE"/> instance from the conversion.</returns>
			public static explicit operator SOCKADDR_STORAGE(in SOCKADDR_IN6 addr)
			{
				using var mem = SafeHGlobalHandle.CreateFromStructure(addr);
				mem.Size = Marshal.SizeOf(typeof(SOCKADDR_STORAGE));
				return mem.ToStructure<SOCKADDR_STORAGE>();
			}

			/// <summary>Performs an explicit conversion from <see cref="SOCKADDR_IN"/> to <see cref="SOCKADDR_STORAGE"/>.</summary>
			/// <param name="addr">The address.</param>
			/// <returns>The resulting <see cref="SOCKADDR_STORAGE"/> instance from the conversion.</returns>
			public static explicit operator SOCKADDR_STORAGE(in SOCKADDR_IN addr)
			{
				using var mem = SafeHGlobalHandle.CreateFromStructure(addr);
				mem.Size = Marshal.SizeOf(typeof(SOCKADDR_STORAGE));
				return mem.ToStructure<SOCKADDR_STORAGE>();
			}

			/// <summary>Performs an explicit conversion from <see cref="SOCKADDR"/> to <see cref="SOCKADDR_STORAGE"/>.</summary>
			/// <param name="addr">The address.</param>
			/// <returns>The resulting <see cref="SOCKADDR_STORAGE"/> instance from the conversion.</returns>
			public static explicit operator SOCKADDR_STORAGE(SOCKADDR addr)
			{
				using var mem = new SafeHGlobalHandle(addr.GetAddressBytes());
				mem.Size = Marshal.SizeOf(typeof(SOCKADDR_STORAGE));
				return mem.ToStructure<SOCKADDR_STORAGE>();
			}

			/// <summary>Performs an explicit conversion from <see cref="IPAddress"/> to <see cref="SOCKADDR_STORAGE"/>.</summary>
			/// <param name="addr">The address.</param>
			/// <returns>The resulting <see cref="SOCKADDR_STORAGE"/> instance from the conversion.</returns>
			public static explicit operator SOCKADDR_STORAGE(IPAddress addr)
			{
				using var mem = new SafeHGlobalHandle(addr.GetAddressBytes());
				mem.Size = Marshal.SizeOf(typeof(SOCKADDR_STORAGE));
				return mem.ToStructure<SOCKADDR_STORAGE>();
			}

			/// <summary>Performs an explicit conversion from <see cref="SOCKADDR_STORAGE"/> to <see cref="SOCKADDR"/>.</summary>
			/// <param name="addr">The addr.</param>
			/// <returns>The resulting <see cref="SOCKADDR"/> instance from the conversion.</returns>
			public static explicit operator SOCKADDR(SOCKADDR_STORAGE addr) => SOCKADDR.CreateFromStructure(addr);
		}

		/// <summary>The <c>SOCKET_ADDRESS</c> structure stores protocol-specific address information.</summary>
		/// <remarks>
		/// <para>
		/// The SOCKADDR structure pointed to by the <c>lpSockaddr</c> member varies depending on the protocol or address family selected.
		/// For example, the <c>sockaddr_in6</c> structure is used for an IPv6 socket address while the <c>sockaddr_in4</c> structure is
		/// used for an IPv4 socket address. The address family is the first member of all of the <c>SOCKADDR</c> structures. The address
		/// family is used to determine which structure is used.
		/// </para>
		/// <para>
		/// On the Microsoft Windows Software Development Kit (SDK) released for Windows Vista and later, the organization of header files
		/// has changed and the <c>SOCKET_ADDRESS</c> structure is defined in the Ws2def.h header file. Note that the Ws2def.h header file
		/// is automatically included in Winsock2.h, and should never be used directly.
		/// </para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/ws2def/ns-ws2def-socket_address typedef struct _SOCKET_ADDRESS { LPSOCKADDR
		// lpSockaddr; INT iSockaddrLength; } SOCKET_ADDRESS, *PSOCKET_ADDRESS, *LPSOCKET_ADDRESS;
		[PInvokeData("ws2def.h", MSDNShortId = "37fbcb96-a859-4eca-8928-8051f95407b9")]
		[StructLayout(LayoutKind.Sequential)]
		public struct SOCKET_ADDRESS
		{
			/// <summary>A pointer to a socket address represented as a SOCKADDR structure.</summary>
			public IntPtr lpSockaddr;

			/// <summary>The length, in bytes, of the socket address.</summary>
			public int iSockaddrLength;

			/// <summary>Gets the <see cref="SOCKADDR_INET"/> from this instance.</summary>
			/// <returns>The <see cref="SOCKADDR_INET"/> value pointed to by this instance.</returns>
			public SOCKADDR_INET GetSOCKADDR() => lpSockaddr.ToStructure<SOCKADDR_INET>();

			/// <summary>Converts to string.</summary>
			/// <returns>A <see cref="System.String"/> that represents this instance.</returns>
			public override string ToString() => GetSOCKADDR().ToString();
		}

		/// <summary>The SOCKET_ADDRESS_LIST structure defines a variable-sized list of transport addresses.</summary>
		/// <remarks>
		/// <para>
		/// A WSK application passes a buffer to the WskControlSocket function when the WSK application queries the current list of local
		/// transport addresses that match a socket's address family. If the call to the <c>WskControlSocket</c> function succeeds, the
		/// buffer contains a SOCKET_ADDRESS_LIST structure followed by the SOCKADDR structures for each of the local transport addresses
		/// that match the socket's address family. The WSK subsystem fills in the <c>Address</c> array and sets the <c>iAddressCount</c>
		/// member to the number of entries in the array. The <c>lpSockaddr</c> pointers in each of the SOCKET_ADDRESS structures in the
		/// array point to the specific SOCKADDR structure type that corresponds to the address family that the WSK application specified
		/// when it created the socket.
		/// </para>
		/// <para>For more information about querying the current list of local transport addresses, see SIO_ADDRESS_LIST_QUERY.</para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/ws2def/ns-ws2def-socket_address_list typedef struct _SOCKET_ADDRESS_LIST { INT
		// iAddressCount; SOCKET_ADDRESS Address[1]; } SOCKET_ADDRESS_LIST, *PSOCKET_ADDRESS_LIST, *LPSOCKET_ADDRESS_LIST;
		[PInvokeData("ws2def.h", MSDNShortId = "b005200b-b0c2-4f19-8765-cd26fbfc0cff")]
		[VanaraMarshaler(typeof(SafeAnysizeStructMarshaler<SOCKET_ADDRESS_LIST>), nameof(iAddressCount))]
		[StructLayout(LayoutKind.Sequential)]
		public struct SOCKET_ADDRESS_LIST
		{
			/// <summary>The number of transport addresses in the list.</summary>
			public int iAddressCount;

			/// <summary>A variable-sized array of SOCKET_ADDRESS structures. The SOCKET_ADDRESS structure is defined as follows:</summary>
			[MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)]
			public SOCKET_ADDRESS[] Address;
		}

		/// <summary>
		/// The <c>SOCKET_PROCESSOR_AFFINITY</c> structure contains the association between a socket and an RSS processor core and NUMA node..
		/// </summary>
		/// <remarks>
		/// <para>
		/// The <c>SOCKET_PROCESSOR_AFFINITY</c> structure is supported on Windows 8, and Windows Server 2012, and later versions of the
		/// operating system.
		/// </para>
		/// <para>
		/// The SIO_QUERY_RSS_PROCESSOR_INFO IOCTL is used to determine the association between a socket and an RSS processor core and NUMA
		/// node. This IOCTL returns a <c>SOCKET_PROCESSOR_AFFINITY</c> structure that contains the processor number and the NUMA node ID.
		/// </para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/ws2def/ns-ws2def-socket_processor_affinity typedef struct
		// _SOCKET_PROCESSOR_AFFINITY { PROCESSOR_NUMBER Processor; USHORT NumaNodeId; USHORT Reserved; } SOCKET_PROCESSOR_AFFINITY, *PSOCKET_PROCESSOR_AFFINITY;
		[PInvokeData("ws2def.h", MSDNShortId = "CB1E9F79-C6BD-40C2-8D0F-36B24B1BBBF4")]
		[StructLayout(LayoutKind.Sequential)]
		public struct SOCKET_PROCESSOR_AFFINITY
		{
			/// <summary>
			/// A structure to represent a system wide processor number. This PROCESSOR_NUMBER structure contains a group number and
			/// relative processor number within the group.
			/// </summary>
			public Kernel32.PROCESSOR_NUMBER Processor;

			/// <summary>The NUMA node ID.</summary>
			public ushort NumaNodeId;

			/// <summary>A value reserved for future use.</summary>
			public ushort Reserved;
		}

		/// <summary>The <c>WSABUF</c> structure enables the creation or manipulation of a data buffer used by some Winsock functions.</summary>
		// https://docs.microsoft.com/en-us/windows/desktop/api/ws2def/ns-ws2def-_wsabuf typedef struct _WSABUF { ULONG len; CHAR *buf; }
		// WSABUF, *LPWSABUF;
		[PInvokeData("ws2def.h", MSDNShortId = "a012c3ba-67fd-4fcf-84d1-85e9d495c29c")]
		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
		public struct WSABUF
		{
			/// <summary>The length of the buffer, in bytes.</summary>
			public uint len;

			/// <summary>A pointer to the buffer.</summary>
			public IntPtr buf;
		}

		/// <summary>
		/// The <c>WSAMSG</c> structure is used with the WSARecvMsg and WSASendMsg functions to store address and optional control
		/// information about connected and unconnected sockets as well as an array of buffers used to store message data.
		/// </summary>
		/// <remarks>
		/// <para>
		/// In the Microsoft Windows Software Development Kit (SDK), the version of this structure for use on Windows Vistais defined with
		/// the data type for the <c>dwBufferCount</c> and <c>dwFlags</c> members as a <c>ULONG</c>. When compiling an application if the
		/// target platform is Windows Vista and later ( <c>NTDDI_VERSION &gt;= NTDDI_LONGHORN, _WIN32_WINNT &gt;= 0x0600</c>, or <c>WINVER
		/// &gt;= 0x0600</c>), the data type for the <c>dwBufferCount</c> and <c>dwFlags</c> members is a <c>ULONG</c>.
		/// </para>
		/// <para>
		/// <c>Windows Server 2003 and Windows XP:</c> When compiling an application, the data type for the <c>dwBufferCount</c> and
		/// <c>dwFlags</c> members is a <c>DWORD</c>.
		/// </para>
		/// <para>
		/// On the Windows SDK released for Windows Vista and later, the <c>WSAMSG</c> structure is defined in the Ws2def.h header file.
		/// Note that the Ws2def.h header file is automatically included in Winsock2.h, and should never be used directly
		/// </para>
		/// <para>
		/// If the datagram or control data is truncated during the transmission, the function being used in association with the
		/// <c>WSAMSG</c> structure returns SOCKET_ERROR and a call to the WSAGetLastError function returns WSAEMSGSIZE. It is up to the
		/// application to determine what was truncated by checking for MSG_TRUNC and/or MSG_CTRUNC flags.
		/// </para>
		/// <para>Use of the Control Member</para>
		/// <para>
		/// The following table summarizes the various uses of control data available for use in the <c>Control</c> member for IPv4 and IPv6.
		/// </para>
		/// <list type="table">
		/// <listheader>
		/// <term>Protocol</term>
		/// <term>cmsg_level</term>
		/// <term>cmsg_type</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>IPv4</term>
		/// <term>IPPROTO_IP</term>
		/// <term>IP_ORIGINAL_ARRIVAL_IF</term>
		/// <term>
		/// Receives the original IPv4 arrival interface where the packet was received for datagram sockets. This control data is used by
		/// firewalls when a Teredo, 6to4, or ISATAP tunnel is used for IPv4 NAT traversal. The cmsg_data[] member in the WSAMSG structure
		/// is a ULONG that contains the IF_INDEX defined in the Ifdef.h header file. For more information, see the IPPROTO_IP Socket
		/// Options for the IP_ORIGINAL_ARRIVAL_IF socket option. Windows Server 2008, Windows Vista, Windows Server 2003 and Windows XP:
		/// The IP_ORIGINAL_ARRIVAL_IF cmsg_type is not supported.
		/// </term>
		/// </item>
		/// <item>
		/// <term>IPv4</term>
		/// <term>IPPROTO_IP</term>
		/// <term>IP_PKTINFO</term>
		/// <term>Specifies/receives packet information for an IPv4 socket. For more information, see the IP_PKTINFO socket option.</term>
		/// </item>
		/// <item>
		/// <term>IPv6</term>
		/// <term>IPPROTO_IPV6</term>
		/// <term>IPV6_DSTOPTS</term>
		/// <term>Specifies/receives destination options.</term>
		/// </item>
		/// <item>
		/// <term>IPv6</term>
		/// <term>IPPROTO_IPV6</term>
		/// <term>IPV6_HOPLIMIT</term>
		/// <term>Specifies/receives hop limit. For more information, see the IPPROTO_IPV6 Socket Options for the IPV6_HOPLIMIT socket option.</term>
		/// </item>
		/// <item>
		/// <term>IPv6</term>
		/// <term>IPPROTO_IPV6</term>
		/// <term>IPV6_HOPOPTS</term>
		/// <term>Specifies/receives hop-by-hop options.</term>
		/// </item>
		/// <item>
		/// <term>IPv6</term>
		/// <term>IPPROTO_IPV6</term>
		/// <term>IPV6_NEXTHOP</term>
		/// <term>Specifies next-hop address.</term>
		/// </item>
		/// <item>
		/// <term>IPv6</term>
		/// <term>IPPROTO_IPV6</term>
		/// <term>IPV6_PKTINFO</term>
		/// <term>Specifies/receives packet information for an IPv6 socket. For more information, see the IPV6_PKTINFO socket option.</term>
		/// </item>
		/// <item>
		/// <term>IPv6</term>
		/// <term>IPPROTO_IPV6</term>
		/// <term>IPV6_RTHDR</term>
		/// <term>Specifies/receives routing header.</term>
		/// </item>
		/// </list>
		/// <para>
		/// Control data is made up of one or more control data objects, each beginning with a <c>WSACMSGHDR</c> structure, defined as the following.
		/// </para>
		/// <para>
		/// <c>Note</c> The transport, not the application, fills out the header information in the <c>WSACMSGHDR</c> structure. The
		/// application simply sets the needed socket options and provides the adequate buffer size.
		/// </para>
		/// <para>The members of the <c>WSACMSGHDR</c> structure are as follows:</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Term</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>cmsg_len</term>
		/// <term>
		/// The number of bytes of data starting from the beginning of the WSACMSGHDR to the end of data (excluding padding bytes that may
		/// follow data).
		/// </term>
		/// </item>
		/// <item>
		/// <term>cmsg_level</term>
		/// <term>The protocol that originated the control information.</term>
		/// </item>
		/// <item>
		/// <term>cmsg_type</term>
		/// <term>The protocol-specific type of control information.</term>
		/// </item>
		/// </list>
		/// <para>The following macros are used to navigate the data objects:</para>
		/// <para>
		/// Returns a pointer to the first control data object. Returns a <c>NULL</c> pointer if there is no control data in the
		/// <c>WSAMSG</c> structure, such as when the <c>Control</c> member is a <c>NULL</c> pointer.
		/// </para>
		/// <para>
		/// Returns a pointer to the next control data object, or <c>NULL</c> if there are no more data objects. If the pcmsg parameter is
		/// <c>NULL</c>, a pointer to the first control data object is returned.
		/// </para>
		/// <para>
		/// Returns a pointer to the first byte of data (referred to as the <c>cmsg_data</c> member, though it is not defined in the structure).
		/// </para>
		/// <para>
		/// Returns the total size of a control data object, given the amount of data. Used to allocate the correct amount of buffer space.
		/// Includes alignment padding.
		/// </para>
		/// <para>Returns the value in <c>cmsg_len</c> given the amount of data. Includes alignment padding.</para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/ws2def/ns-ws2def-wsamsg typedef struct _WSAMSG { LPSOCKADDR name; INT namelen;
		// LPWSABUF lpBuffers; #if ... ULONG dwBufferCount; #else DWORD dwBufferCount; #endif WSABUF Control; #if ... ULONG dwFlags; #else
		// DWORD dwFlags; #endif } WSAMSG, *PWSAMSG, *LPWSAMSG;
		[PInvokeData("ws2def.h", MSDNShortId = "105a6e2c-1edf-4ec0-a1c2-ac0bcafeda30")]
		[StructLayout(LayoutKind.Sequential)]
		public struct WSAMSG
		{
			/// <summary>
			/// <para>Type: <c>LPSOCKADDR</c></para>
			/// <para>
			/// A pointer to a SOCKET_ADDRESS structure that stores information about the remote address. Used only with unconnected sockets.
			/// </para>
			/// </summary>
			public IntPtr name;

			/// <summary>
			/// <para>Type: <c>INT</c></para>
			/// <para>
			/// The length, in bytes, of the SOCKET_ADDRESS structure pointed to in the <c>pAddr</c> member. Used only with unconnected sockets.
			/// </para>
			/// </summary>
			public int namelen;

			/// <summary>
			/// <para>Type: <c>LPWSABUF</c></para>
			/// <para>
			/// An array of WSABUF structures used to receive the message data. The capability of the <c>lpBuffers</c> member to contain
			/// multiple buffers enables the use of scatter/gather I/O.
			/// </para>
			/// </summary>
			public IntPtr lpBuffers;

			/// <summary>
			/// <para>Type: <c>DWORD</c></para>
			/// <para>The number of buffers pointed to in the <c>lpBuffers</c> member.</para>
			/// </summary>
			public uint dwBufferCount;

			/// <summary>
			/// <para>Type: <c>WSABUF</c></para>
			/// <para>A structure of WSABUF type used to specify optional control data. See Remarks.</para>
			/// </summary>
			public WSABUF Control;

			/// <summary>
			/// <para>Type: <c>DWORD</c></para>
			/// <para>
			/// One or more control flags, specified as the logical <c>OR</c> of values. The possible values for <c>dwFlags</c> member on
			/// input are defined in the Winsock2.h header file. The possible values for <c>dwFlags</c> member on output are defined in the
			/// Ws2def.h header file which is automatically included by the Winsock2.h header file.
			/// </para>
			/// <list type="table">
			/// <listheader>
			/// <term>Flags on input</term>
			/// <term>Meaning</term>
			/// </listheader>
			/// <item>
			/// <term>MSG_PEEK</term>
			/// <term>
			/// Peek at the incoming data. The data is copied into the buffer, but is not removed from the input queue. This flag is valid
			/// only for non-overlapped sockets.
			/// </term>
			/// </item>
			/// </list>
			/// <list type="table">
			/// <listheader>
			/// <term>Flag returned</term>
			/// <term>Meaning</term>
			/// </listheader>
			/// <item>
			/// <term>MSG_BCAST</term>
			/// <term>The datagram was received as a link-layer broadcast or with a destination IP address that is a broadcast address.</term>
			/// </item>
			/// <item>
			/// <term>MSG_MCAST</term>
			/// <term>The datagram was received with a destination IP address that is a multicast address.</term>
			/// </item>
			/// <item>
			/// <term>MSG_TRUNC</term>
			/// <term>The datagram was truncated. More data was present than the process allocated room for.</term>
			/// </item>
			/// <item>
			/// <term>MSG_CTRUNC</term>
			/// <term>The control (ancillary) data was truncated. More control data was present than the process allocated room for.</term>
			/// </item>
			/// </list>
			/// </summary>
			public MsgFlags dwFlags;
		}

		/// <summary>
		/// <para>
		/// Some of the socket IOCTL opcodes for Windows Sockets 2 are summarized in the following table. More detailed information is in
		/// the Winsock reference on <c>Winsock IOCTLs</c> and the <c>WSPIoctl</c> function. There are other new protocol-specific IOCTL
		/// opcodes that can be found in the protocol-specific annex.
		/// </para>
		/// <para>A complete list of <c>Winsock IOCTLs</c> are available in the Winsock reference.</para>
		/// </summary>
		// https://docs.microsoft.com/en-us/windows/win32/winsock/summary-of-socket-ioctl-opcodes-2
		[PInvokeData("ws2def.h", MSDNShortId = "fb6447b4-28f5-4ab7-bbdc-5a57ed38a994")]
		public static class WinSockIOControlCode
		{
			/// <summary>Requests notification of changes in information reported through SIO_ADDRESS_LIST_QUERY</summary>
			public static readonly uint SIO_ADDRESS_LIST_CHANGE = _WSAIO(IOC_WS2, 23);

			/// <summary>
			/// Obtains a list of local transport addresses of the socket's protocol family to which the application can bind. The list of
			/// addresses varies based on address family and some addresses are excluded from the list.
			/// </summary>
			[CorrespondingType(typeof(SOCKET_ADDRESS), CorrespondingAction.Get)]
			public static readonly uint SIO_ADDRESS_LIST_QUERY = _WSAIOR(IOC_WS2, 22);

			/// <summary>
			/// Allows application developers to sort a list of IPv6 and IPv4 destination addresses to determine the best available address
			/// for making a connection.
			/// </summary>
			[CorrespondingType(typeof(SOCKET_ADDRESS_LIST), CorrespondingAction.GetSet)]
			public static readonly uint SIO_ADDRESS_LIST_SORT = _WSAIORW(IOC_WS2, 25);

			/// <summary>Associates the socket with the specified handle of a companion interface.</summary>
			public static readonly uint SIO_ASSOCIATE_HANDLE = _WSAIOW(IOC_WS2, 1);

			/// <summary>Enables circular queuing.</summary>
			public static readonly uint SIO_ENABLE_CIRCULAR_QUEUEING = _WSAIO(IOC_WS2, 2);

			/// <summary>Requests the route to the specified address to be discovered.</summary>
			[CorrespondingType(typeof(SOCKADDR), CorrespondingAction.Set)]
			public static readonly uint SIO_FIND_ROUTE = _WSAIOR(IOC_WS2, 3);

			/// <summary>Discards current contents of the sending queue.</summary>
			public static readonly uint SIO_FLUSH = _WSAIO(IOC_WS2, 4);

			/// <summary>Retrieves the protocol-specific broadcast address to be used in WSPSendTo.</summary>
			[CorrespondingType(typeof(SOCKADDR), CorrespondingAction.Get)]
			public static readonly uint SIO_GET_BROADCAST_ADDRESS = _WSAIOR(IOC_WS2, 5);

			/// <summary>Gets the function pointer for the WSASendMsg function obtained at run time.</summary>
			public static readonly uint SIO_GET_EXTENSION_FUNCTION_POINTER = _WSAIORW(IOC_WS2, 6);

			/// <summary>Reserved.</summary>
			[CorrespondingType(typeof(QOS), CorrespondingAction.Get)]
			public static readonly uint SIO_GET_GROUP_QOS = _WSAIORW(IOC_WS2, 8);

			/// <summary>Retrieves current flow specifications for the socket.</summary>
			[CorrespondingType(typeof(QOS), CorrespondingAction.Get)]
			public static readonly uint SIO_GET_QOS = _WSAIORW(IOC_WS2, 7);

			/// <summary>Specifies the scope over which multicast transmissions will occur.</summary>
			[CorrespondingType(typeof(int), CorrespondingAction.Set)]
			public static readonly uint SIO_MULTICAST_SCOPE = _WSAIOW(IOC_WS2, 10);

			/// <summary>Controls whether data sent in a multipoint session will also be received by the same socket on the local host.</summary>
			[CorrespondingType(typeof(BOOL), CorrespondingAction.Set)]
			public static readonly uint SIO_MULTIPOINT_LOOPBACK = _WSAIOW(IOC_WS2, 9);

			/// <summary>Queries the association between a socket and an RSS processor core and NUMA node.</summary>
			[CorrespondingType(typeof(SOCKET_PROCESSOR_AFFINITY), CorrespondingAction.Get)]
			public static readonly uint SIO_QUERY_RSS_PROCESSOR_INFO = _WSAIOR(IOC_WS2, 37);

			/// <summary>Obtains socket descriptor of the next provider in the chain on which current socket depends in regards to PnP.</summary>
			[CorrespondingType(typeof(SOCKET), CorrespondingAction.Get)]
			public static readonly uint SIO_QUERY_TARGET_PNP_HANDLE = _WSAIOR(IOC_WS2, 24);

			/// <summary>
			/// Requests notification of changes in information reported through SIO_ROUTING_INTERFACE_QUERY for the specified address.
			/// </summary>
			[CorrespondingType(typeof(SOCKADDR), CorrespondingAction.Set)]
			public static readonly uint SIO_ROUTING_INTERFACE_CHANGE = _WSAIOW(IOC_WS2, 21);

			/// <summary>Obtains the address of the local interface that should be used to send to the specified address.</summary>
			[CorrespondingType(typeof(SOCKADDR), CorrespondingAction.GetSet)]
			public static readonly uint SIO_ROUTING_INTERFACE_QUERY = _WSAIORW(IOC_WS2, 20);

			/// <summary>Reserved.</summary>
			[CorrespondingType(typeof(QOS), CorrespondingAction.Set)]
			public static readonly uint SIO_SET_GROUP_QOS = _WSAIOW(IOC_WS2, 12);

			/// <summary>Establishes new flow specifications for the socket.</summary>
			[CorrespondingType(typeof(QOS), CorrespondingAction.Set)]
			public static readonly uint SIO_SET_QOS = _WSAIOW(IOC_WS2, 11);

			/// <summary>Obtains a corresponding handle for socket s that is valid in the context of a companion interface.</summary>
			[CorrespondingType(typeof(int), CorrespondingAction.Set)]
			public static readonly uint SIO_TRANSLATE_HANDLE = _WSAIORW(IOC_WS2, 13);

			private const uint IOC_PROTOCOL = 0x10000000;
			private const uint IOC_UNIX = 0x00000000;
			private const uint IOC_VENDOR = 0x18000000;
			private const uint IOC_WS2 = 0x08000000;
			private const uint IOC_WSK = IOC_WS2 | 0x07000000;

			private static uint _WSAIO(uint x, uint y) => (IOC_VOID | (x) | (y));

			private static uint _WSAIOR(uint x, uint y) => (IOC_OUT | (x) | (y));

			private static uint _WSAIORW(uint x, uint y) => (IOC_INOUT | (x) | (y));

			private static uint _WSAIOW(uint x, uint y) => (IOC_IN | (x) | (y));
		}
	}
}