views:

227

answers:

2

I'm trying to interact with a native DLL using P/Invoke, but it requires an in_addr struct parameter. I keep seeing many different kinds of definitions for it, but which is the best to use?

Also, how can I convert a C# IPAddress object to an in_addr struct?

+2  A: 

Try the following

[StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
public struct in_addr {

    /// Anonymous1
    public Anonymous1 S_un;
}

[StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Explicit)]
public struct Anonymous1 {

    /// Anonymous2
    [System.Runtime.InteropServices.FieldOffsetAttribute(0)]
    public Anonymous2 S_un_b;

    /// Anonymous3
    [System.Runtime.InteropServices.FieldOffsetAttribute(0)]
    public Anonymous3 S_un_w;

    /// u_long->unsigned int
    [System.Runtime.InteropServices.FieldOffsetAttribute(0)]
    public uint S_addr;
}

[StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
public struct Anonymous2 {

    /// u_char->unsigned char
    public byte s_b1;

    /// u_char->unsigned char
    public byte s_b2;

    /// u_char->unsigned char
    public byte s_b3;

    /// u_char->unsigned char
    public byte s_b4;
}

[StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
public struct Anonymous3 {

    /// u_short->unsigned short
    public ushort s_w1;

    /// u_short->unsigned short
    public ushort s_w2;
}

Generated with PInvoke Interop Assistant

EDIT Cleaned up the anonymous names.

JaredPar
Is there any way to convert that to and from an IPAddress object?
David Brown
@David, there is no built-in function but it shouldn't be too terrible to code up.
JaredPar
I haven't had much experience with C, so let me know if I have this right. I used BitConverter to convert the IPAddress' bytes to an Int32, then assigned it to S_addr (casting it to uint). The 4 byte fields (s_b1-s_b4) in Anonymous2 are assigned each of the first 4 bytes from the IPAddress' byte array. Will that work? What should I do with s_w1 and s_w2?
David Brown
@David, Been awhile since i used in_addr but that looks correct. I don't remember off the top fo my head what s_w1 and s_w2 do but I think leaving them as the default of 0 is correct.
JaredPar
+2  A: 

In case anyone is interested, here is the full code. It's capable of unpacking an IPAddress object to an in_addr struct and back again.

[StructLayout(LayoutKind.Sequential)]
public struct in_addr {
    public Anonymous1 S_un;

    [StructLayoutAttribute(LayoutKind.Explicit)]
    public struct Anonymous1 {
        [FieldOffsetAttribute(0)]
        public Anonymous2 S_un_b;

        [FieldOffsetAttribute(0)]
        public Anonymous3 S_un_w;

        [FieldOffsetAttribute(0)]
        public uint S_addr;
    }

    [StructLayoutAttribute(LayoutKind.Sequential)]
    public struct Anonymous2 {
        public byte s_b1;
        public byte s_b2;
        public byte s_b3;
        public byte s_b4;
    }

    [StructLayoutAttribute(LayoutKind.Sequential)]
    public struct Anonymous3 {
        public ushort s_w1;
        public ushort s_w2;
    }

    public in_addr(IPAddress address) : this(address.GetAddressBytes()) { }

    public in_addr(byte[] address) {
        // Set this first, otherwise it wipes out the other fields
        S_un.S_un_w = new Anonymous3();

        S_un.S_addr = (uint)BitConverter.ToInt32(address, 0);

        S_un.S_un_b.s_b1 = address[0];
        S_un.S_un_b.s_b2 = address[1];
        S_un.S_un_b.s_b3 = address[2];
        S_un.S_un_b.s_b4 = address[3];
    }

    /// <summary>
    /// Unpacks an in_addr struct to an IPAddress object
    /// </summary>
    /// <returns></returns>
    public IPAddress ToIPAddress() {
        byte[] bytes = new[] {
            S_un.S_un_b.s_b1,
            S_un.S_un_b.s_b2,
            S_un.S_un_b.s_b3,
            S_un.S_un_b.s_b4
        };
    }

    return new IPAddress(bytes);
}

Like JaredPar, I still don't know what to do with Anonymous3, but it doesn't really matter because it can't be set anyway. Since they all have the same FieldOffset, setting one field clears all of the others. It appears to work, though, so I'm not too worried about it.

David Brown