3

P/Invoked ネイティブ関数から、構造体IntPtrを指す を取得します。sockaddrどうすればに変換できIPAddressますか?

ありがとう!

4

3 に答える 3

5

@aevitas の回答に続いて、次の解決策を思いつきました。

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));
  }
}

IPv4 アドレスと IPv6 アドレスの両方でテストに成功しました。

于 2013-07-02T16:22:27.003 に答える
2

型を型に直接変換するMarshalことはできないため、最初にマネージド構造体を作成してマーシャリングする必要があります。sockaddrIPAddress

[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;
    }
}

次に、次のようなものから型Marshal.PtrToStructureを取得するために使用できます。sockaddr_inIntPtr

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

その後、IPAddress取得したデータから新しいオブジェクトを作成するのは非常に簡単です。

上記の例にADDRESS_FAMILIES含まれる列挙型は、http: //pastie.org/8103489で見つけることができます。EnumLib

pinvoke.net には元々構造体のメンバーが他にもあります。興味がある場合はこちらを参照してください。ただし、この特定の状況ではまったく必要ないと思います。

于 2013-07-02T13:50:20.923 に答える