Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to convert IntPtr/Int to Socket?

I want to convert message.WParam to Socket.

    protected override void WndProc(ref Message m)
    {
        if (m.Msg == Values.MESSAGE_ASYNC)
        {

            switch (m.LParam.ToInt32())
            {
                case Values.FD_READ:
                    WS2.Receive(m.WParam);
                case Values.FD_WRITE: break;
                default: break;
            }

        }
        else
        {
            base.WndProc(ref m);
        }
    }

public class WS2
{
    public static void Receive(IntPtr sock)
    {
        Socket socket = sock;
    }
}

How to convert the IntrPtr(sock) to Socket so I can call Receive()?

like image 582
Ivan Prodanov Avatar asked Apr 19 '09 12:04

Ivan Prodanov


2 Answers

You can't do it because the Socket class creates and manages its own private socket handle. In theory you could use some evil reflection to jamb your socket handle into a private field of a Socket but that's a total hack and I wouldn't do it.

Given a valid socket handle, you can receive data by calling the Win32 recv function via P/Invoke, like this:

[DllImport("ws2_32.dll")]
extern static int recv([In] IntPtr socketHandle, [In] IntPtr buffer,
  [In] int count, [In] SocketFlags socketFlags);

/// <summary>
/// Receives data from a socket.
/// </summary>
/// <param name="socketHandle">The socket handle.</param>
/// <param name="buffer">The buffer to receive.</param>
/// <param name="offset">The offset within the buffer.</param>
/// <param name="size">The number of bytes to receive.</param>
/// <param name="socketFlags">The socket flags.</param>
/// <exception cref="ArgumentException">If <paramref name="socketHandle"/>
/// is zero.</exception>
/// <exception cref="ArgumentNullException">If <paramref name="buffer"/>
/// is null.</exception>
/// <exception cref="ArgumentOutOfRangeException">If the 
/// <paramref name="offset"/> and <paramref name="size"/> specify a range
/// outside the given buffer.</exception>
public static int Receive(IntPtr socketHandle, byte[] buffer, int offset,
  int size, SocketFlags socketFlags)
{
  if (socketHandle == IntPtr.Zero)
    throw new ArgumentException("socket");
  if (buffer == null)
    throw new ArgumentNullException("buffer");
  if (offset < 0 || offset >= buffer.Length)
    throw new ArgumentOutOfRangeException("offset");
  if (size < 0 || offset + size > buffer.Length)
    throw new ArgumentOutOfRangeException("size");

  unsafe
  {
    fixed (byte* pData = buffer)
    {
      return Recv(socketHandle, new IntPtr(pData + offset),
        size, socketFlags);
    }
  }
}
like image 82
JayMcClellan Avatar answered Nov 02 '22 03:11

JayMcClellan


There's nothing in the Socket class to do this - though it uses an underlying handle, there's no API to manipulate it and the Handle property is read-only.

You would probably be best off by just P/Invoking recv and calling it directly with your IntPtr handle.

A quick browse of the Rotor code looks like you could get away with creating a Socket, closing it's handle, and then setting it's m_handle field to your own. But that requires Reflection, and if your socket is already connected (which it sounds like it is - since you just asked about calling recv) then you'd also have to manipulate the private state of Socket - which makes this idea even less palatable and more fragile.

like image 41
Mark Brackett Avatar answered Nov 02 '22 04:11

Mark Brackett