c# type-conversion pinvoke ip-address intptr

C#- Convirtiendo IntPtr apuntando a la estructura sockaddr a IPAddress



type-conversion pinvoke (3)

Desde una función nativa P / invocada, obtengo un IntPtr que apunta a una estructura sockaddr . ¿Cómo puedo convertirlo a una IPAddress ?

¡Gracias!


Como no se puede IPAddress directamente un tipo de IPAddress en un tipo de IPAddress , IPAddress se debe crear una estructura administrada para IPAddress :

[StructLayout(LayoutKind.Sequential)] internal struct sockaddr_in { internal EnumLib.ADDRESS_FAMILIES sin_family; internal ushort sin_port; internal in_addr sin_addr; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] internal byte[] sin_zero; internal static sockaddr_in FromString(string host, int port) { var sockaddr = new sockaddr_in(); var lpAddressLength = Marshal.SizeOf(sockaddr); WSAStringToAddress(host + ":" + port, EnumLib.ADDRESS_FAMILIES.AF_INET, IntPtr.Zero, ref sockaddr, ref lpAddressLength); return sockaddr; } }

A continuación, puede usar Marshal.PtrToStructure para obtener un tipo de IntPtr su IntPtr la IntPtr manera:

(sockaddr_in) Marshal.PtrToStructure(address, typeof(sockaddr_in));

Después de eso, debería ser bastante simple crear un nuevo objeto IPAddress partir de los datos que acaba de recuperar.

Puede encontrar la enumeración ADDRESS_FAMILIES que está contenida en EnumLib en el ejemplo anterior aquí: http://pastie.org/8103489

Originalmente hay más miembros de struct en pinvoke.net, solo échale un vistazo aquí si estás interesado en ellos, pero creo que no los necesitarás en absoluto en esta situación específica.


Debes crear la estructura correspondiente en C #. El uso del siguiente código ( p es usted IntPtr ):

(MyStruct)System.Runtime.InteropServices.Marshal.PtrToStructure(p, typeof(MyStruct));

Puedes "leerlo" en C #. El resto del código es fácil, porque tendrá una dirección IP en sa_data


Siguiendo la respuesta de @aevitas, se me ocurrió la siguiente solución:

public enum SockAddrFamily { Inet = 2, Inet6 = 23 } [StructLayout(LayoutKind.Sequential)] public struct SockAddr { public ushort Family; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 14)] public byte[] Data; }; [StructLayout(LayoutKind.Sequential)] public struct SockAddrIn { public ushort Family; public ushort Port; public uint Addr; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public byte[] Zero; } [StructLayout(LayoutKind.Sequential)] public struct SockAddrIn6 { public ushort Family; public ushort Port; public uint FlowInfo; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] public byte[] Addr; public uint ScopeId; }; public IPAddress ConvertSockAddrPtrToIPAddress(IntPtr sockAddrPtr) { SockAddr sockAddr = (SockAddr)Marshal.PtrToStructure(sockAddrPtr, typeof(SockAddr)); switch ((SockAddrFamily)sockAddr.Family) { case SockAddrFamily.Inet: { SockAddrIn sockAddrIn = (SockAddrIn)Marshal.PtrToStructure(sockAddrPtr, typeof(SockAddrIn)); return new IPAddress(sockAddrIn.Addr); } case SockAddrFamily.Inet6: { SockAddrIn6 sockAddrIn6 = (SockAddrIn6)Marshal.PtrToStructure(sockAddrPtr, typeof(SockAddrIn6)); return new IPAddress(sockAddrIn6.Addr); } default: throw new Exception(string.Format("Non-IP address family: {0}", sockAddr.Family)); } }

Lo probé con éxito con direcciones IPv4 e IPv6.