// see c sharp version: http://www.pcreview.co.uk/forums/thread-2096837.php
program getservbynameProj;

{$APPTYPE CONSOLE}

uses
  System.Diagnostics,
  System.Runtime.InteropServices;


type WSock = class
  public
    class procedure Initialize();
    class procedure ShutDown();

    class function GetServiceByName( strName: System.String; strProtocol: System.String): System.Int32;
end;

const
  WSADESCRIPTION_LEN = 256;
  WSASYS_STATUS_LEN = 128;

type
[StructLayoutAttribute(LayoutKind.Sequential)]  
TWsaData=record
  wVersion : Int16;
  wHighVersion : Int16;
  [MarshalAs(UnmanagedType.ByValTStr,SizeConst=WSADESCRIPTION_LEN +1)]
  szDescription : string;
  [MarshalAs(UnmanagedType.ByValTStr,SizeConst=WSASYS_STATUS_LEN +1)]
  szSystemStatus: string;
  iMaxSockets : Int16;
  iMaxUdpDg : Int16;
  lpVendorInfo : IntPtr;
end;

type
[StructLayoutAttribute(LayoutKind.Sequential)]
TServent = record
  s_name : String;
  s_aliases: IntPtr;
  s_port: Int32;
  s_proto: String;
end;

[DllImport('Ws2_32.dll', EntryPoint='getservbyname', SetLastError=true,
CharSet=CharSet.Ansi, ExactSpelling=true, CallingConvention=CallingConvention.StdCall)]
function getservbyname(strName: string; strProto: string): IntPtr; external;

[DllImport('Ws2_32.dll', EntryPoint='WSAGetLastError', SetLastError=true,
CharSet=CharSet.Ansi, ExactSpelling=true, CallingConvention=CallingConvention.StdCall)]
function WSAGetLastError(): Int32; external;

function WSAStartup(wVersionRequired: Int32; var lpWSDATA: TWsaData): Int32; stdcall; external 'wsock32.dll';
function WSACleanup(): Int32; stdcall; external 'wsock32.dll';

class procedure WSock.Initialize();
var
  WSAD: TWsaData;
  iVal: Int32;
begin
  iVal := WSAStartup(1 + (1 shl 8), WSAD);
  if (iVal <> 0) then
  begin
    Marshal.ThrowExceptionForHR( WSAGetLastError( ) );
  end;
  Console.WriteLine(WSAD.szDescription);
end;

class procedure WSock.Shutdown();
var
  iVal: Int32;
begin
  iVal := WSACleanup();
  if (iVal <> 0) then
  begin
    Marshal.ThrowExceptionForHR( WSAGetLastError( ) );
  end;
end;

class function WSock.GetServiceByName( strName: System.String; strProtocol: System.String): System.Int32;
var
  serventPtr: IntPtr;
  servent: TServent;
  i: Int32;
begin
  serventPtr := getservbyname(strName, strProtocol);
  if (serventPtr = nil) then
  begin
    i := WSAGetLastError( );
    Marshal.ThrowExceptionForHR( i );
    System.Console.WriteLine(i.ToString());
  end
  else
  begin
    servent := TServent(Marshal.PtrToStructure(serventPtr, TypeOf(TServent)));
    result := ((servent.s_port and $ff) shl 8) + (servent.s_port shr 8);
  end;
end;

begin
  WSock.Initialize();

  System.Console.WriteLine(WSock.GetServiceByName('knetd', 'tcp'));
  System.Console.WriteLine(WSock.GetServiceByName('conference', 'tcp'));
  System.Console.ReadLine();
  WSock.ShutDown();

end.