GetExtendedTcpTable でソケットのプロセスIDを調べる

Windowsnetstat -ano のような、ソケット一覧にプロセスIDがついたものを出力するコード。
GetTcpTable() ではプロセスIDが出ないしAllocateAndGetTcpExTableFromStackはdeprecatedで、GetExtendedTcpTable はXP SP2とVistaで使える。はず。

using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using System.Runtime.InteropServices;

namespace readTCPTable {
  public class ByteParser {
    byte[] buf;uint size;int next;
    public ByteParser(byte[] b,uint s) {buf=b;size=s;next=0;}
    public uint readUI32() {uint r = BitConverter.ToUInt32(buf,next);next += 4;return r;}
    // ネットワークバイトオーダの16ビット値
    public uint readNUI16() {uint r = (((uint)buf[next])<<8)|((uint)buf[next+1]);next +=2;return r;}
  };
  public class TCPTableReader {

    public enum TCP_TABLE_CLASS{ TCP_TABLE_BASIC_LISTENER, TCP_TABLE_BASIC_CONNECTIONS, TCP_TABLE_BASIC_ALL, TCP_TABLE_OWNER_PID_LISTENER, TCP_TABLE_OWNER_PID_CONNECTIONS, TCP_TABLE_OWNER_PID_ALL, TCP_TABLE_OWNER_MODULE_LISTENER, TCP_TABLE_OWNER_MODULE_CONNECTIONS, TCP_TABLE_OWNER_MODULE_ALL };

    public enum TCPState : uint {None = 0, CLOSED, LISTEN, SYN_SENT, SYN_RCVD, ESTABLISHED, FIN_WAIT1, FIN_WAIT2, CLOSE_WAIT, CLOSING,LAST_ACK, TIME_WAIT,DELETE_TCB, };

    [DllImport("iphlpapi.dll",SetLastError=true)]
    public static extern int GetExtendedTcpTable( byte[] pTcpTable, out uint dwOutBufLen, bool sort, int ipVersion, TCP_TABLE_CLASS tblClass, int reserved );

    public static string stringIPv4(uint v) {
      byte[] ip=BitConverter.GetBytes(v);
      return String.Format("{0}.{1}.{2}.{3}",ip[0],ip[1],ip[2],ip[3]);
    }
    public const int AF_INET = 2; // IP_v4
    public const int NO_ERROR = 0;

    public static bool readTCPTable(){

      // バッファサイズ調査を兼ねて2回呼ぶ
      uint buffer_size = 1;
      byte[] buffer = new byte[buffer_size];
      int AF_INET = 2; // IP_v4
      if( NO_ERROR != GetExtendedTcpTable(
        buffer,out buffer_size, // 出力バッファとそのサイズ
        true, // TCP endpoints を降順ソートするなら真
        AF_INET, // IPv4 or IPv6
        TCP_TABLE_CLASS.TCP_TABLE_OWNER_PID_ALL, // one of the values from the TCP_TABLE_CLASS enumeration
        0 // Reserved
      )){
        buffer = new byte[buffer_size];
        if( NO_ERROR != GetExtendedTcpTable(
          buffer,out buffer_size, // 出力バッファとそのサイズ
          true, // TCP endpoints を降順ソートするなら真
          AF_INET, // IPv4 or IPv6
          TCP_TABLE_CLASS.TCP_TABLE_OWNER_PID_ALL, // one of the values from the TCP_TABLE_CLASS enumeration
          0 // Reserved
        )){
          return false;
        }
      }

      ByteParser bp = new ByteParser(buffer,buffer_size);
      uint nRows = bp.readUI32();
      for(int i=0;i<nRows;++i){
        TCPState state = (TCPState)bp.readUI32();
        uint local_addr = bp.readUI32();
        uint local_port = bp.readNUI16();bp.readNUI16();
        uint remote_addr = bp.readUI32();
        uint remote_port = bp.readNUI16();bp.readNUI16();
        uint pid = bp.readUI32();
        if(remote_addr==0) remote_port=0;
        Debug.WriteLine(String.Format("{1}#{2} {3}#{4} {5} {0}" ,state ,stringIPv4(local_addr),local_port ,stringIPv4(remote_addr),remote_port ,pid ));
      }
      return true;
    }

    // エントリポイント
    static void Main(string[] args) {
      readTCPTable();
    }
  }
}