Win32 API 日本語リファレンス
ホームNetworkManagement.IpHelper › GetPerTcp6ConnectionEStats

GetPerTcp6ConnectionEStats

関数
指定IPv6 TCP接続の拡張統計(ESTATS)情報を取得する。
DLLIPHLPAPI.dll呼出規約winapi対応OSWindows Vista 以降

シグネチャ

// IPHLPAPI.dll
#include <windows.h>

DWORD GetPerTcp6ConnectionEStats(
    MIB_TCP6ROW* Row,
    TCP_ESTATS_TYPE EstatsType,
    BYTE* Rw,   // optional
    DWORD RwVersion,
    DWORD RwSize,
    BYTE* Ros,   // optional
    DWORD RosVersion,
    DWORD RosSize,
    BYTE* Rod,   // optional
    DWORD RodVersion,
    DWORD RodSize
);

パラメーター

名前方向説明
RowMIB_TCP6ROW*inIPv6 TCP 接続を表す MIB_TCP6ROW 構造体へのポインター。
EstatsTypeTCP_ESTATS_TYPEin

要求する TCP 拡張統計の種類。このパラメーターは、呼び出しが成功した場合に RwRodRos の各パラメーターで返される情報のデータと形式を決定します。

このパラメーターには、Tcpestats.h ヘッダー ファイルで定義されている TCP_ESTATS_TYPE 列挙型の値のいずれかを指定できます。

説明
TcpConnectionEstatsSynOpts
この値は、TCP 接続の SYN 交換情報を要求します。

この列挙値では、読み取り専用の静的情報のみが利用できます。

Ros パラメーターが NULL でなく、関数が成功した場合、Ros パラメーターが指すバッファーには TCP_ESTATS_SYN_OPTS_ROS_v0 構造体が格納されます。

TcpConnectionEstatsData
この値は、TCP 接続の拡張データ転送情報を要求します。

この列挙値では、読み取り専用の動的情報と読み取り/書き込み情報のみが利用できます。

Rw パラメーターが NULL でなく、関数が成功した場合、Rw パラメーターが指すバッファーには TCP_ESTATS_DATA_RW_v0 構造体が格納されます。

この TCP 接続で拡張データ転送情報が有効になっており、Rod パラメーターが NULL でなく、関数が成功した場合、Rod パラメーターが指すバッファーには TCP_ESTATS_DATA_ROD_v0 構造体が格納されます。

TcpConnectionEstatsSndCong
この値は、TCP 接続の送信側輻輳情報を要求します。

この列挙値では、3 種類すべての情報 (読み取り専用の静的情報、読み取り専用の動的情報、読み取り/書き込み情報) が利用できます。

Rw パラメーターが NULL でなく、関数が成功した場合、Rw パラメーターが指すバッファーには TCP_ESTATS_SND_CONG_RW_v0 構造体が格納されます。

Ros パラメーターが NULL でなく、関数が成功した場合、Ros パラメーターが指すバッファーには TCP_ESTATS_SND_CONG_ROS_v0 構造体が格納されます。

この TCP 接続で送信側輻輳情報が有効になっており、Rod パラメーターが NULL でなく、関数が成功した場合、Rod パラメーターが指すバッファーには TCP_ESTATS_SND_CONG_ROD_v0 構造体が格納されます。

TcpConnectionEstatsPath
この値は、TCP 接続の拡張パス測定情報を要求します。

この列挙値では、読み取り専用の動的情報と読み取り/書き込み情報のみが利用できます。

Rw パラメーターが NULL でなく、関数が成功した場合、Rw パラメーターが指すバッファーには TCP_ESTATS_PATH_RW_v0 構造体が格納されます。

この TCP 接続で拡張パス測定情報が有効になっており、Rod パラメーターが NULL でなく、関数が成功した場合、Rod パラメーターが指すバッファーには TCP_ESTATS_PATH_ROD_v0 構造体が格納されます。

TcpConnectionEstatsSendBuff
この値は、TCP 接続の拡張出力キューイング情報を要求します。

この列挙値では、読み取り専用の動的情報と読み取り/書き込み情報のみが利用できます。

Rw パラメーターが NULL でなく、関数が成功した場合、Rw パラメーターが指すバッファーには TCP_ESTATS_SEND_BUFF_RW_v0 構造体が格納されます。

この TCP 接続で拡張出力キューイング情報が有効になっており、Rod パラメーターが NULL でなく、関数が成功した場合、Rod パラメーターが指すバッファーには TCP_ESTATS_SEND_BUFF_ROD_v0 構造体が格納されます。

TcpConnectionEstatsRec
この値は、TCP 接続の拡張ローカル受信側情報を要求します。

この列挙値では、読み取り専用の動的情報と読み取り/書き込み情報のみが利用できます。

Rw パラメーターが NULL でなく、関数が成功した場合、Rw パラメーターが指すバッファーには TCP_ESTATS_REC_RW_v0 構造体が格納されます。

この TCP 接続で拡張ローカル受信側情報が有効になっており、Rod パラメーターが NULL でなく、関数が成功した場合、Rod パラメーターが指すバッファーには TCP_ESTATS_REC_ROD_v0 構造体が格納されます。

TcpConnectionEstatsObsRec
この値は、TCP 接続の拡張リモート受信側情報を要求します。

この列挙値では、読み取り専用の動的情報と読み取り/書き込み情報のみが利用できます。

Rw パラメーターが NULL でなく、関数が成功した場合、Rw パラメーターが指すバッファーには TCP_ESTATS_OBS_REC_RW_v0 構造体が格納されます。

この TCP 接続で拡張リモート受信側情報が有効になっており、Rod パラメーターが NULL でなく、関数が成功した場合、Rod パラメーターが指すバッファーには TCP_ESTATS_OBS_REC_ROD_v0 構造体が格納されます。

TcpConnectionEstatsBandwidth
この値は、TCP 接続の帯域幅推定統計を要求します。

この列挙値では、読み取り専用の動的情報と読み取り/書き込み情報のみが利用できます。

Rw パラメーターが NULL でなく、関数が成功した場合、Rw パラメーターが指すバッファーには TCP_ESTATS_BANDWIDTH_RW_v0 構造体が格納されます。

この TCP 接続で帯域幅推定統計が有効になっており、Rod パラメーターが NULL でなく、関数が成功した場合、Rod パラメーターが指すバッファーには TCP_ESTATS_BANDWIDTH_ROD_v0 構造体が格納されます。

TcpConnectionEstatsFineRtt
この値は、TCP 接続のきめ細かいラウンドトリップ時間 (RTT) 推定統計を要求します。

この列挙値では、読み取り専用の動的情報と読み取り/書き込み情報のみが利用できます。

Rw パラメーターが NULL でなく、関数が成功した場合、Rw パラメーターが指すバッファーには TCP_ESTATS_FINE_RTT_RW_v0 構造体が格納されます。

この TCP 接続できめ細かい RTT 推定統計が有効になっており、Rod パラメーターが NULL でなく、関数が成功した場合、Rod パラメーターが指すバッファーには TCP_ESTATS_FINE_RTT_ROD_v0 構造体が格納されます。

RwBYTE*outoptional読み取り/書き込み情報を受け取るバッファーへのポインター。アプリケーションが TCP 接続の読み取り/書き込み情報を取得しない場合、このパラメーターは NULL ポインターでもかまいません。
RwVersionDWORDin要求する読み取り/書き込み情報のバージョン。現在サポートされている値はバージョン 0 です。
RwSizeDWORDinRw パラメーターが指すバッファーのサイズ (バイト単位)。
RosBYTE*outoptional読み取り専用の静的情報を受け取るバッファーへのポインター。アプリケーションが TCP 接続の読み取り専用の静的情報を取得しない場合、このパラメーターは NULL ポインターでもかまいません。
RosVersionDWORDin要求する読み取り専用の静的情報のバージョン。現在サポートされている値はバージョン 0 です。
RosSizeDWORDinRos パラメーターが指すバッファーのサイズ (バイト単位)。
RodBYTE*outoptional読み取り専用の動的情報を受け取るバッファーへのポインター。アプリケーションが TCP 接続の読み取り専用の動的情報を取得しない場合、このパラメーターは NULL ポインターでもかまいません。
RodVersionDWORDin要求する読み取り専用の動的情報のバージョン。現在サポートされている値はバージョン 0 です。
RodSizeDWORDinRod パラメーターが指すバッファーのサイズ (バイト単位)。

戻り値の型: DWORD

公式ドキュメント

IPv6 TCP 接続の拡張統計情報を取得します。

戻り値

関数が成功した場合、戻り値は NO_ERROR です。

関数が失敗した場合、戻り値は次のいずれかのエラー コードです。

戻りコード 説明
ERROR_INSUFFICIENT_BUFFER
関数に渡されたバッファーが小さすぎます。このエラーは、RwRos、または Rod パラメーターが指すバッファーがデータを受け取るのに十分な大きさでない場合に返されます。また、RwRos、または Rod パラメーターが指すバッファーの 1 つが NULL であるにもかかわらず、対応する RwSizeRosSize、または RodSize に長さが指定されている場合にも返されます。

このエラー値は Windows Vista および Windows Server 2008 で返されます。

ERROR_INVALID_PARAMETER
パラメーターが正しくありません。このエラーは、Row パラメーターが NULL ポインターの場合に返されます。
ERROR_INVALID_USER_BUFFER
指定されたユーザー バッファーが、要求された操作に対して無効です。このエラーは、RwRos、または Rod パラメーターが指すバッファーの 1 つが NULL であるにもかかわらず、対応する RwSizeRosSize、または RodSize に長さが指定されている場合に返されます。その結果、次のいずれかの条件を満たす場合にこのエラーが返されます。
  • Row パラメーターが NULL ポインターであり、RwSize パラメーターが 0 以外である。
  • Ros パラメーターが NULL ポインターであり、RosSize パラメーターが 0 以外である。
  • Rod パラメーターが NULL ポインターであり、RodSize パラメーターが 0 以外である。

このエラー値は Windows 7 および Windows Server 2008 R2 で返されます。

ERROR_NOT_FOUND
要求されたエントリが見つかりませんでした。このエラーは、Row パラメーターで指定された TCP 接続が見つからなかった場合に返されます。
ERROR_NOT_SUPPORTED
要求はサポートされていません。このエラーは、RwVersionRosVersion、または RodVersion パラメーターが 0 に設定されていない場合に返されます。
Other
FormatMessage を使用して、返されたエラーのメッセージ文字列を取得してください。

解説(Remarks)

GetPerTcp6ConnectionEStats 関数は Windows Vista 以降で定義されています。

GetPerTcp6ConnectionEStats 関数は、ネットワークとアプリケーションの両方におけるパフォーマンスの問題を診断するために TCP を使用するように設計されています。ネットワーク ベースのアプリケーションのパフォーマンスが低い場合、TCP はボトルネックが送信側、受信側、またはネットワーク自体のいずれにあるかを判断できます。ボトルネックがネットワークにある場合、TCP はその性質に関する具体的な情報を提供できます。

GetPerTcp6ConnectionEStats 関数は、Row パラメーターで渡された IPv6 TCP 接続の拡張統計情報を取得します。取得する拡張統計の種類は EstatsType パラメーターで指定します。TcpConnectionEstatsSynOptsEstatsType パラメーターに渡される場合を除き、この TCP 接続の拡張統計はすべての TCP_ESTATS_TYPE 値について、事前に SetPerTcp6ConnectionEStats 関数の呼び出しによって有効化されている必要があります。

GetTcp6Table 関数は、ローカル コンピューター上の IPv6 TCP 接続テーブルを取得するために使用します。この関数は、MIB_TCP6ROW エントリの配列を含む MIB_TCP6TABLE 構造体を返します。GetPerTcp6ConnectionEStats 関数に渡す Row パラメーターは、既存の IPv6 TCP 接続のエントリである必要があります。

現在サポートされている TCP 接続統計のバージョンはバージョン 0 のみです。したがって、GetPerTcp6ConnectionEStats に渡す RwVersionRosVersionRodVersion の各パラメーターは 0 に設定する必要があります。

IPv4 接続の拡張 TCP 統計については、GetPerTcpConnectionEStats および SetPerTcpConnectionEStats 関数を参照してください。

SetPerTcp6ConnectionEStats 関数は、Administrators グループのメンバーとしてログオンしたユーザーのみが呼び出すことができます。Administrators グループのメンバーでないユーザーが SetPerTcp6ConnectionEStats を呼び出した場合、関数呼び出しは失敗し、ERROR_ACCESS_DENIED が返されます。この関数は、Windows Vista 以降のユーザー アカウント制御 (UAC) が原因で失敗することもあります。この関数を含むアプリケーションが、組み込みの Administrator 以外の Administrators グループのメンバーとしてログオンしたユーザーによって実行される場合、アプリケーションのマニフェスト ファイルで requestedExecutionLevel が requireAdministrator に設定されていない限り、この呼び出しは失敗します。アプリケーションにこのマニフェスト ファイルがない場合、組み込みの Administrator 以外の Administrators グループのメンバーとしてログオンしたユーザーは、この関数が成功するために、組み込みの Administrator として昇格されたシェル (管理者として実行) でアプリケーションを実行する必要があります。

GetPerTcp6ConnectionEStats の呼び出し元は、返された Rw 構造体の EnableCollection フィールドを確認し、それが TRUE でない場合は Ros および Rod 構造体のデータを無視する必要があります。EnableCollectionFALSE に設定されている場合、Ros および Rod で返されるデータは未定義です。たとえば、これが発生する条件の 1 つは、GetPerTcp6ConnectionEStats を使用して IPv6 TCP 接続の拡張統計を取得し、かつ事前に SetPerTcp6ConnectionEStats を呼び出して拡張統計を有効化した場合です。SetPerTcp6ConnectionEStats の呼び出しが失敗した場合、その後の GetPerTcp6ConnectionEStats の呼び出しは、拡張 TCP 統計ではなく無意味なランダム データを返します。以下の例を管理者として、また通常のユーザーとしての両方で実行することで、この例を観察できます。

次の例は、IPv4 および IPv6 の TCP 接続の TCP 拡張統計を取得し、返されたデータの値を出力します。

// Need to link with Iphlpapi.lib and Ws2_32.lib
// Need to run as administrator

#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif

#include <windows.h>
#include <winsock2.h>
#include <Ws2tcpip.h>
#include <iphlpapi.h>
#include <Tcpestats.h>
#include <stdlib.h>
#include <stdio.h>

// Need to link with Iphlpapi.lib
#pragma comment(lib, "iphlpapi.lib")

// Need to link with Ws2_32.lib
#pragma comment(lib, "ws2_32.lib")

// An array of name for the TCP_ESTATS_TYPE enum values
// The names values must match the enum values
const wchar_t* estatsTypeNames[] = {
    L"TcpConnectionEstatsSynOpts",
    L"TcpConnectionEstatsData",
    L"TcpConnectionEstatsSndCong",
    L"TcpConnectionEstatsPath",
    L"TcpConnectionEstatsSendBuff",
    L"TcpConnectionEstatsRec",
    L"TcpConnectionEstatsObsRec",
    L"TcpConnectionEstatsBandwidth",
    L"TcpConnectionEstatsFineRtt",
    L"TcpConnectionEstatsMaximum"
};

// Function prototypes

// Run tests for IPv4 or IPv4 TCP extended stats
DWORD RunEstatsTest(bool v6);

// Get an IPv4 TCP row entry
DWORD GetTcpRow(u_short localPort, u_short remotePort,
    MIB_TCP_STATE state, __out PMIB_TCPROW row);

// Get an IPv6 TCP row entry
DWORD GetTcp6Row(u_short localPort, u_short remotePort,
    MIB_TCP_STATE state, __out PMIB_TCP6ROW row);

// Enable or disable the supplied Estat type on a TCP connection
void ToggleEstat(PVOID row, TCP_ESTATS_TYPE type, bool enable, bool v6);

// Toggle all Estats for a TCP connection
void ToggleAllEstats(void* row, bool enable, bool v6);

// Dump the supplied Estate type data on the given TCP connection row
void GetAndOutputEstats(void* row, TCP_ESTATS_TYPE type, bool v6);

//
void GetAllEstats(void* row, bool v6);

// Creates a TCP server and client socket on the loopback address.
// Binds the server socket to a port.
// Establishes a client TCP connection to the server 
int CreateTcpConnection(bool v6, SOCKET* serviceSocket, SOCKET* clientSocket,
    SOCKET* acceptSocket, u_short* serverPort,
    u_short* clientPort);

//
// Entry point.
//
int __cdecl main()
{
    RunEstatsTest(FALSE);
    RunEstatsTest(TRUE);
    return (0);
}

//
// Create connect and listen sockets on loopback interface and dump all Estats
// types on the created TCP connections for the supplied IP address type.
//
DWORD RunEstatsTest(bool v6)
{
    SOCKET serviceSocket, clientSocket, acceptSocket;
    serviceSocket = clientSocket = acceptSocket = INVALID_SOCKET;
    MIB_TCPROW server4ConnectRow, client4ConnectRow;
    MIB_TCP6ROW server6ConnectRow, client6ConnectRow;
    void* serverConnectRow, * clientConnectRow = NULL;
    bool bWSAStartup = false;

    char* buff = (char*)malloc(1000);
    if (buff == NULL) {
        wprintf(L"\nFailed to allocate memory.");
        goto bail;
    }

    if (v6) {
        serverConnectRow = &server6ConnectRow;
        clientConnectRow = &client6ConnectRow;
    }
    else {
        serverConnectRow = &server4ConnectRow;
        clientConnectRow = &client4ConnectRow;
    }

    UINT winStatus;
    int sockStatus;
    u_short serverPort, clientPort;

    //
    // Initialize Winsock.
    //
    WSADATA wsaData;
    winStatus = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (winStatus != ERROR_SUCCESS) {
        wprintf(L"\nFailed to open winsock. Error %d", winStatus);
        goto bail;
    }

    bWSAStartup = true;

    //
    // Create TCP connection on which Estats information will be collected.
    // Obtain port numbers of created connections.
    //
    winStatus =
        CreateTcpConnection(v6, &serviceSocket, &clientSocket, &acceptSocket,
            &serverPort, &clientPort);
    if (winStatus != ERROR_SUCCESS) {
        wprintf(L"\nFailed to create TCP connection. Error %d", winStatus);
        goto bail;
    }
    //
    // Obtain MIB_TCPROW corresponding to the TCP connection.
    //
    winStatus = v6 ?
        GetTcp6Row(serverPort, clientPort, MIB_TCP_STATE_ESTAB,
            (PMIB_TCP6ROW)serverConnectRow) :
        GetTcpRow(serverPort, clientPort, MIB_TCP_STATE_ESTAB,
            (PMIB_TCPROW)serverConnectRow);
    if (winStatus != ERROR_SUCCESS) {
        wprintf
        (L"\nGetTcpRow failed on the server established connection with %d",
            winStatus);
        goto bail;
    }

    winStatus = v6 ?
        GetTcp6Row(clientPort, serverPort, MIB_TCP_STATE_ESTAB,
            (PMIB_TCP6ROW)clientConnectRow) :
        GetTcpRow(clientPort, serverPort, MIB_TCP_STATE_ESTAB,
            (PMIB_TCPROW)clientConnectRow);
    if (winStatus != ERROR_SUCCESS) {
        wprintf
        (L"\nGetTcpRow failed on the client established connection with %d",
            winStatus);
        goto bail;
    }
    //
    // Enable Estats collection and dump current stats.
    //
    ToggleAllEstats(serverConnectRow, TRUE, v6);
    ToggleAllEstats(clientConnectRow, TRUE, v6);
    wprintf(L"\n\n\nDumping Estats for server socket:\n");
    GetAllEstats(serverConnectRow, v6);
    wprintf(L"\n\n\nDumping Estats for client connect socket:\n");
    GetAllEstats(clientConnectRow, v6);

    //
    // Initiate TCP data transfers to see effect on Estats counters.
    //
    sockStatus = send(clientSocket, buff, (int)(1000 * sizeof(char)), 0);
    if (sockStatus == SOCKET_ERROR) {
        wprintf(L"\nFailed to send from client to server %d",
            WSAGetLastError());
    }
    else {
        sockStatus = recv(acceptSocket, buff, (int)(1000 * sizeof(char)), 0);
        if (sockStatus == SOCKET_ERROR) {
            wprintf(L"\nFailed to receive data on the server %d",
                WSAGetLastError());
        }
    }

    //
    // Dump updated Estats and disable Estats collection.
    //
    wprintf
    (L"\n\n\nDumping Estats for server socket after client sends data:\n");
    GetAllEstats(serverConnectRow, v6);
    wprintf
    (L"\n\n\nDumping Estats for client socket after client sends data:\n");
    GetAllEstats(clientConnectRow, v6);
    ToggleAllEstats(serverConnectRow, FALSE, v6);
    ToggleAllEstats(clientConnectRow, FALSE, v6);

bail:
    if (serviceSocket != INVALID_SOCKET)
        closesocket(serviceSocket);
    if (clientSocket != INVALID_SOCKET)
        closesocket(clientSocket);
    if (acceptSocket != INVALID_SOCKET)
        closesocket(acceptSocket);
    if (buff != NULL)
        free(buff);
    if (bWSAStartup)
        WSACleanup();
    return ERROR_SUCCESS;
}

int CreateTcpConnection(bool v6,
    SOCKET* serviceSocket,
    SOCKET* clientSocket,
    SOCKET* acceptSocket,
    u_short* serverPort, u_short* clientPort)
{
    INT status;
    ADDRINFOW hints, * localhost = NULL;
    const wchar_t* loopback;
    loopback = v6 ? L"::1" : L"127.0.0.1";
    int aiFamily = v6 ? AF_INET6 : AF_INET;
    int nameLen = sizeof(SOCKADDR_STORAGE);

    *serviceSocket = INVALID_SOCKET;
    *clientSocket = INVALID_SOCKET;
    *acceptSocket = INVALID_SOCKET;

    ZeroMemory(&hints, sizeof(hints));
    hints.ai_family = aiFamily;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;

    status = GetAddrInfoW(loopback, L"", &hints, &localhost);
    if (status != ERROR_SUCCESS) {
        wprintf(L"\nFailed to open localhost. Error %d", status);
        goto bail;
    }

    *serviceSocket = socket(aiFamily, SOCK_STREAM, IPPROTO_TCP);
    if (*serviceSocket == INVALID_SOCKET) {
        wprintf(L"\nFailed to create server socket. Error %d",
            WSAGetLastError());
        goto bail;
    }

    *clientSocket = socket(aiFamily, SOCK_STREAM, IPPROTO_TCP);
    if (*clientSocket == INVALID_SOCKET) {
        wprintf(L"\nFailed to create client socket. Error %d",
            WSAGetLastError());
        goto bail;
    }

    status =
        bind(*serviceSocket, localhost->ai_addr, (int)localhost->ai_addrlen);
    if (status == SOCKET_ERROR) {
        wprintf(L"\nFailed to bind server socket to loopback. Error %d",
            WSAGetLastError());
        goto bail;
    }

    if (localhost != NULL) {
        FreeAddrInfoW(localhost);
        localhost = NULL;
    }

    SOCKADDR_STORAGE serverSockName, clientSockName;
    status = getsockname(*serviceSocket,
        (sockaddr*)&serverSockName, &nameLen);
    if (status == SOCKET_ERROR) {
        wprintf(L"\ngetsockname failed %d", WSAGetLastError());
        goto bail;
    }
    if (v6) {
        *serverPort = ((sockaddr_in6*)(&serverSockName))->sin6_port;
    }
    else {
        *serverPort = ((sockaddr_in*)(&serverSockName))->sin_port;
    }

    status = listen(*serviceSocket, SOMAXCONN);
    if (status == SOCKET_ERROR) {
        wprintf(L"\nFailed to listen on server socket. Error %d",
            WSAGetLastError());
        goto bail;
    }

    status =
        connect(*clientSocket, (sockaddr*)&serverSockName,
            (int)sizeof(SOCKADDR_STORAGE));
    if (status == SOCKET_ERROR) {
        wprintf(L"\nCould not connect client and server sockets %d",
            WSAGetLastError());
        goto bail;
    }

    status = getsockname(*clientSocket,
        (sockaddr*)&clientSockName, &nameLen);
    if (status == SOCKET_ERROR) {
        wprintf(L"\ngetsockname failed %d", WSAGetLastError());
        goto bail;
    }
    if (v6) {
        *clientPort = ((sockaddr_in6*)(&clientSockName))->sin6_port;
    }
    else {
        *clientPort = ((sockaddr_in*)(&clientSockName))->sin_port;
    }

    *acceptSocket = accept(*serviceSocket, NULL, NULL);
    if (*acceptSocket == INVALID_SOCKET) {
        wprintf(L"\nFailed to accept socket connection %d", WSAGetLastError());
        goto bail;
    }

    return ERROR_SUCCESS;

bail:
    if (localhost != NULL)
        FreeAddrInfoW(localhost);

    if (*serviceSocket != INVALID_SOCKET) {
        closesocket(*serviceSocket);
        *serviceSocket = INVALID_SOCKET;
    }

    if (*clientSocket != INVALID_SOCKET) {
        closesocket(*clientSocket);
        *clientSocket = INVALID_SOCKET;
    }

    if (*acceptSocket != INVALID_SOCKET) {
        closesocket(*acceptSocket);
        *acceptSocket = INVALID_SOCKET;
    }

    return status;
}

void GetAllEstats(void* row, bool v6)
{
    GetAndOutputEstats(row, TcpConnectionEstatsSynOpts, v6);
    GetAndOutputEstats(row, TcpConnectionEstatsData, v6);
    GetAndOutputEstats(row, TcpConnectionEstatsSndCong, v6);
    GetAndOutputEstats(row, TcpConnectionEstatsPath, v6);
    GetAndOutputEstats(row, TcpConnectionEstatsSendBuff, v6);
    GetAndOutputEstats(row, TcpConnectionEstatsRec, v6);
    GetAndOutputEstats(row, TcpConnectionEstatsObsRec, v6);
    GetAndOutputEstats(row, TcpConnectionEstatsBandwidth, v6);
    GetAndOutputEstats(row, TcpConnectionEstatsFineRtt, v6);
}

//
// Returns a MIB_TCPROW corresponding to the local port, remote port and state
// filter parameters.
//
DWORD
GetTcpRow(u_short localPort,
    u_short remotePort, MIB_TCP_STATE state, __out PMIB_TCPROW row)
{
    PMIB_TCPTABLE tcpTable = NULL;
    PMIB_TCPROW tcpRowIt = NULL;

    DWORD status, size = 0, i;
    bool connectionFound = FALSE;

    status = GetTcpTable(tcpTable, &size, TRUE);
    if (status != ERROR_INSUFFICIENT_BUFFER) {
        return status;
    }

    tcpTable = (PMIB_TCPTABLE)malloc(size);
    if (tcpTable == NULL) {
        return ERROR_OUTOFMEMORY;
    }

    status = GetTcpTable(tcpTable, &size, TRUE);
    if (status != ERROR_SUCCESS) {
        free(tcpTable);
        return status;
    }

    for (i = 0; i < tcpTable->dwNumEntries; i++) {
        tcpRowIt = &tcpTable->table[i];
        if (tcpRowIt->dwLocalPort == (DWORD)localPort &&
            tcpRowIt->dwRemotePort == (DWORD)remotePort &&
            tcpRowIt->State == state) {
            connectionFound = TRUE;
            *row = *tcpRowIt;
            break;
        }
    }

    free(tcpTable);

    if (connectionFound) {
        return ERROR_SUCCESS;
    }
    else {
        return ERROR_NOT_FOUND;
    }
}

//
// Returns a MIB_TCP6ROW corresponding to the local port, remote port and state
// filter parameters. This is a v6 equivalent of the GetTcpRow function.
//
DWORD
GetTcp6Row(u_short localPort,
    u_short remotePort, MIB_TCP_STATE state, __out PMIB_TCP6ROW row)
{
    PMIB_TCP6TABLE tcp6Table = NULL;
    PMIB_TCP6ROW tcp6RowIt = NULL;

    DWORD status, size = 0, i;
    bool connectionFound = FALSE;

    status = GetTcp6Table(tcp6Table, &size, TRUE);
    if (status != ERROR_INSUFFICIENT_BUFFER) {
        return status;
    }

    tcp6Table = (PMIB_TCP6TABLE)malloc(size);
    if (tcp6Table == NULL) {
        return ERROR_OUTOFMEMORY;
    }

    status = GetTcp6Table(tcp6Table, &size, TRUE);
    if (status != ERROR_SUCCESS) {
        free(tcp6Table);
        return status;
    }

    for (i = 0; i < tcp6Table->dwNumEntries; i++) {
        tcp6RowIt = &tcp6Table->table[i];
        if (tcp6RowIt->dwLocalPort == (DWORD)localPort &&
            tcp6RowIt->dwRemotePort == (DWORD)remotePort &&
            tcp6RowIt->State == state) {
            connectionFound = TRUE;
            *row = *tcp6RowIt;
            break;
        }
    }

    free(tcp6Table);

    if (connectionFound) {
        return ERROR_SUCCESS;
    }
    else {
        return ERROR_NOT_FOUND;
    }
}

//
// Enable or disable the supplied Estat type on a TCP connection.
//
void ToggleEstat(PVOID row, TCP_ESTATS_TYPE type, bool enable, bool v6)
{
    TCP_BOOLEAN_OPTIONAL operation =
        enable ? TcpBoolOptEnabled : TcpBoolOptDisabled;
    ULONG status, size = 0;
    PUCHAR rw = NULL;
    TCP_ESTATS_DATA_RW_v0 dataRw;
    TCP_ESTATS_SND_CONG_RW_v0 sndRw;
    TCP_ESTATS_PATH_RW_v0 pathRw;
    TCP_ESTATS_SEND_BUFF_RW_v0 sendBuffRw;
    TCP_ESTATS_REC_RW_v0 recRw;
    TCP_ESTATS_OBS_REC_RW_v0 obsRecRw;
    TCP_ESTATS_BANDWIDTH_RW_v0 bandwidthRw;
    TCP_ESTATS_FINE_RTT_RW_v0 fineRttRw;

    switch (type) {
    case TcpConnectionEstatsData:
        dataRw.EnableCollection = enable;
        rw = (PUCHAR)&dataRw;
        size = sizeof(TCP_ESTATS_DATA_RW_v0);
        break;

    case TcpConnectionEstatsSndCong:
        sndRw.EnableCollection = enable;
        rw = (PUCHAR)&sndRw;
        size = sizeof(TCP_ESTATS_SND_CONG_RW_v0);
        break;

    case TcpConnectionEstatsPath:
        pathRw.EnableCollection = enable;
        rw = (PUCHAR)&pathRw;
        size = sizeof(TCP_ESTATS_PATH_RW_v0);
        break;

    case TcpConnectionEstatsSendBuff:
        sendBuffRw.EnableCollection = enable;
        rw = (PUCHAR)&sendBuffRw;
        size = sizeof(TCP_ESTATS_SEND_BUFF_RW_v0);
        break;

    case TcpConnectionEstatsRec:
        recRw.EnableCollection = enable;
        rw = (PUCHAR)&recRw;
        size = sizeof(TCP_ESTATS_REC_RW_v0);
        break;

    case TcpConnectionEstatsObsRec:
        obsRecRw.EnableCollection = enable;
        rw = (PUCHAR)&obsRecRw;
        size = sizeof(TCP_ESTATS_OBS_REC_RW_v0);
        break;

    case TcpConnectionEstatsBandwidth:
        bandwidthRw.EnableCollectionInbound = operation;
        bandwidthRw.EnableCollectionOutbound = operation;
        rw = (PUCHAR)&bandwidthRw;
        size = sizeof(TCP_ESTATS_BANDWIDTH_RW_v0);
        break;

    case TcpConnectionEstatsFineRtt:
        fineRttRw.EnableCollection = enable;
        rw = (PUCHAR)&fineRttRw;
        size = sizeof(TCP_ESTATS_FINE_RTT_RW_v0);
        break;

    default:
        return;
        break;
    }

    if (v6) {
        status = SetPerTcp6ConnectionEStats((PMIB_TCP6ROW)row, type,
            rw, 0, size, 0);
    }
    else {
        status = SetPerTcpConnectionEStats((PMIB_TCPROW)row, type,
            rw, 0, size, 0);
    }

    if (status != NO_ERROR) {
        if (v6)
            wprintf(L"\nSetPerTcp6ConnectionEStats %s %s failed. status = %d",
                estatsTypeNames[type], enable ? L"enabled" : L"disabled",
                status);
        else
            wprintf(L"\nSetPerTcpConnectionEStats %s %s failed. status = %d",
                estatsTypeNames[type], enable ? L"enabled" : L"disabled",
                status);
    }
}

//
// Toggle all Estats for a TCP connection.
//
void ToggleAllEstats(void* row, bool enable, bool v6)
{
    ToggleEstat(row, TcpConnectionEstatsData, enable, v6);
    ToggleEstat(row, TcpConnectionEstatsSndCong, enable, v6);
    ToggleEstat(row, TcpConnectionEstatsPath, enable, v6);
    ToggleEstat(row, TcpConnectionEstatsSendBuff, enable, v6);
    ToggleEstat(row, TcpConnectionEstatsRec, enable, v6);
    ToggleEstat(row, TcpConnectionEstatsObsRec, enable, v6);
    ToggleEstat(row, TcpConnectionEstatsBandwidth, enable, v6);
    ToggleEstat(row, TcpConnectionEstatsFineRtt, enable, v6);
}

//
// Call GetPerTcp6ConnectionEStats or GetPerTcpConnectionEStats.
//
ULONG GetConnectionEStats(void* row, TCP_ESTATS_TYPE type, PUCHAR rw, ULONG rwSize, bool v6, PUCHAR ros, ULONG rosSize, PUCHAR rod, ULONG rodSize)
{
    if (v6) {
        return GetPerTcp6ConnectionEStats((PMIB_TCP6ROW)row,
            type,
            rw, 0, rwSize,
            ros, 0, rosSize,
            rod, 0, rodSize);
    }
    else {
        return GetPerTcpConnectionEStats((PMIB_TCPROW)row,
            type,
            rw, 0, rwSize,
            ros, 0, rosSize,
            rod, 0, rodSize);
    }
}

//
// Dump the supplied Estate type on the given TCP connection row.
//
void GetAndOutputEstats(void* row, TCP_ESTATS_TYPE type, bool v6)
{
    ULONG rosSize = 0, rodSize = 0;
    ULONG winStatus;
    PUCHAR ros = NULL, rod = NULL;

    PTCP_ESTATS_SYN_OPTS_ROS_v0 synOptsRos = { 0 };
    PTCP_ESTATS_DATA_ROD_v0 dataRod = { 0 };
    PTCP_ESTATS_SND_CONG_ROD_v0 sndCongRod = { 0 };
    PTCP_ESTATS_SND_CONG_ROS_v0 sndCongRos = { 0 };
    PTCP_ESTATS_PATH_ROD_v0 pathRod = { 0 };
    PTCP_ESTATS_SEND_BUFF_ROD_v0 sndBuffRod = { 0 };
    PTCP_ESTATS_REC_ROD_v0 recRod = { 0 };
    PTCP_ESTATS_OBS_REC_ROD_v0 obsRecRod = { 0 };
    PTCP_ESTATS_BANDWIDTH_ROD_v0 bandwidthRod = { 0 };
    PTCP_ESTATS_FINE_RTT_ROD_v0 fineRttRod = { 0 };

    switch (type) {
    case TcpConnectionEstatsSynOpts:
        rosSize = sizeof(TCP_ESTATS_SYN_OPTS_ROS_v0);
        break;

    case TcpConnectionEstatsData:
        rodSize = sizeof(TCP_ESTATS_DATA_ROD_v0);
        break;

    case TcpConnectionEstatsSndCong:
        rodSize = sizeof(TCP_ESTATS_SND_CONG_ROD_v0);
        rosSize = sizeof(TCP_ESTATS_SND_CONG_ROS_v0);
        break;

    case TcpConnectionEstatsPath:
        rodSize = sizeof(TCP_ESTATS_PATH_ROD_v0);
        break;

    case TcpConnectionEstatsSendBuff:
        rodSize = sizeof(TCP_ESTATS_SEND_BUFF_ROD_v0);
        break;

    case TcpConnectionEstatsRec:
        rodSize = sizeof(TCP_ESTATS_REC_ROD_v0);
        break;

    case TcpConnectionEstatsObsRec:
        rodSize = sizeof(TCP_ESTATS_OBS_REC_ROD_v0);
        break;

    case TcpConnectionEstatsBandwidth:
        rodSize = sizeof(TCP_ESTATS_BANDWIDTH_ROD_v0);
        break;

    case TcpConnectionEstatsFineRtt:
        rodSize = sizeof(TCP_ESTATS_FINE_RTT_ROD_v0);
        break;

    default:
        wprintf(L"\nCannot get type %d", (int)type);
        return;
        break;
    }

    if (rosSize != 0) {
        ros = (PUCHAR)malloc(rosSize);
        if (ros == NULL) {
            wprintf(L"\nOut of memory");
            return;
        }
        else
            memset(ros, 0, rosSize); // zero the buffer
    }
    if (rodSize != 0) {
        rod = (PUCHAR)malloc(rodSize);
        if (rod == NULL) {
            free(ros);
            wprintf(L"\nOut of memory");
            return;
        }
        else
            memset(rod, 0, rodSize); // zero the buffer
    }

    TCP_ESTATS_DATA_RW_v0 dataRw = { 0 };
    TCP_ESTATS_SND_CONG_RW_v0 sndCongRw = { 0 };
    TCP_ESTATS_PATH_RW_v0 pathRw = { 0 };
    TCP_ESTATS_SEND_BUFF_RW_v0 sndBuffRw = { 0 };
    TCP_ESTATS_REC_RW_v0 recRw = { 0 };
    TCP_ESTATS_OBS_REC_RW_v0 obsRecRw = { 0 };
    TCP_ESTATS_BANDWIDTH_RW_v0 bandwidthRw = { 0 };
    TCP_ESTATS_FINE_RTT_RW_v0 fineRttRw = { 0 };
    BOOLEAN RwEnableCollection{ FALSE };

    switch (type) {
    case TcpConnectionEstatsData:
        winStatus = GetConnectionEStats(row, type, (PUCHAR)&dataRw, sizeof(TCP_ESTATS_DATA_RW_v0), v6, ros, rosSize, rod, rodSize);
        RwEnableCollection = dataRw.EnableCollection;
        break;

    case TcpConnectionEstatsSndCong:
        winStatus = GetConnectionEStats(row, type, (PUCHAR)&sndCongRw, sizeof(TCP_ESTATS_SND_CONG_RW_v0), v6, ros, rosSize, rod, rodSize);
        RwEnableCollection = sndCongRw.EnableCollection;
        break;

    case TcpConnectionEstatsPath:
        winStatus = GetConnectionEStats(row, type, (PUCHAR)&pathRw, sizeof(TCP_ESTATS_PATH_RW_v0), v6, ros, rosSize, rod, rodSize);
        RwEnableCollection = pathRw.EnableCollection;
        break;

    case TcpConnectionEstatsSendBuff:
        winStatus = GetConnectionEStats(row, type, (PUCHAR)&sndBuffRw, sizeof(TCP_ESTATS_SEND_BUFF_RW_v0), v6, ros, rosSize, rod, rodSize);
        RwEnableCollection = sndBuffRw.EnableCollection;
        break;

    case TcpConnectionEstatsRec:
        winStatus = GetConnectionEStats(row, type, (PUCHAR)&recRw, sizeof(TCP_ESTATS_REC_RW_v0), v6, ros, rosSize, rod, rodSize);
        RwEnableCollection = recRw.EnableCollection;
        break;

    case TcpConnectionEstatsObsRec:
        winStatus = GetConnectionEStats(row, type, (PUCHAR)&obsRecRw, sizeof(TCP_ESTATS_OBS_REC_RW_v0), v6, ros, rosSize, rod, rodSize);
        RwEnableCollection = obsRecRw.EnableCollection;
        break;

    case TcpConnectionEstatsBandwidth:
        winStatus = GetConnectionEStats(row, type, (PUCHAR)&bandwidthRw, sizeof(TCP_ESTATS_BANDWIDTH_RW_v0), v6, ros, rosSize, rod, rodSize);
        RwEnableCollection = bandwidthRw.EnableCollectionOutbound && bandwidthRw.EnableCollectionInbound;
        break;

    case TcpConnectionEstatsFineRtt:
        winStatus = GetConnectionEStats(row, type, (PUCHAR)&fineRttRw, sizeof(TCP_ESTATS_FINE_RTT_RW_v0), v6, ros, rosSize, rod, rodSize);
        RwEnableCollection = fineRttRw.EnableCollection;
        break;

    default:
        winStatus = GetConnectionEStats(row, type, NULL, v6, 0, ros, rosSize, rod, rodSize);
        break;
    }

    if (!RwEnableCollection) {
        if (v6)
            wprintf(L"\nGetPerTcp6ConnectionEStats %s failed. Rw.EnableCollection == FALSE", estatsTypeNames[type]);
        else
            wprintf(L"\nGetPerTcpConnectionEStats %s failed. Rw.EnableCollection == FALSE", estatsTypeNames[type]);
        return;
    }

    if (winStatus != NO_ERROR) {
        if (v6)
            wprintf(L"\nGetPerTcp6ConnectionEStats %s failed. status = %d",
                estatsTypeNames[type],
                winStatus);
        else
            wprintf(L"\nGetPerTcpConnectionEStats %s failed. status = %d",
                estatsTypeNames[type],
                winStatus);
    }
    else {
        switch (type) {
        case TcpConnectionEstatsSynOpts:
            synOptsRos = (PTCP_ESTATS_SYN_OPTS_ROS_v0)ros;
            wprintf(L"\nSyn Opts");
            wprintf(L"\nActive Open:    %s",
                synOptsRos->ActiveOpen ? L"Yes" : L"No");
            wprintf(L"\nMss Received:   %u", synOptsRos->MssRcvd);
            wprintf(L"\nMss Sent        %u", synOptsRos->MssSent);
            break;

        case TcpConnectionEstatsData:
            dataRod = (PTCP_ESTATS_DATA_ROD_v0)rod;
            wprintf(L"\n\nData");
            wprintf(L"\nBytes Out:   %lu", dataRod->DataBytesOut);
            wprintf(L"\nSegs Out:    %lu", dataRod->DataSegsOut);
            wprintf(L"\nBytes In:    %lu", dataRod->DataBytesIn);
            wprintf(L"\nSegs In:     %lu", dataRod->DataSegsIn);
            wprintf(L"\nSegs Out:    %u", dataRod->SegsOut);
            wprintf(L"\nSegs In:     %u", dataRod->SegsIn);
            wprintf(L"\nSoft Errors: %u", dataRod->SoftErrors);
            wprintf(L"\nSoft Error Reason: %u", dataRod->SoftErrorReason);
            wprintf(L"\nSnd Una:     %u", dataRod->SndUna);
            wprintf(L"\nSnd Nxt:     %u", dataRod->SndNxt);
            wprintf(L"\nSnd Max:     %u", dataRod->SndMax);
            wprintf(L"\nBytes Acked: %lu", dataRod->ThruBytesAcked);
            wprintf(L"\nRcv Nxt:     %u", dataRod->RcvNxt);
            wprintf(L"\nBytes Rcv:   %lu", dataRod->ThruBytesReceived);
            break;

        case TcpConnectionEstatsSndCong:
            sndCongRod = (PTCP_ESTATS_SND_CONG_ROD_v0)rod;
            sndCongRos = (PTCP_ESTATS_SND_CONG_ROS_v0)ros;
            wprintf(L"\n\nSnd Cong");
            wprintf(L"\nTrans Rwin:       %u", sndCongRod->SndLimTransRwin);
            wprintf(L"\nLim Time Rwin:    %u", sndCongRod->SndLimTimeRwin);
            wprintf(L"\nLim Bytes Rwin:   %u", sndCongRod->SndLimBytesRwin);
            wprintf(L"\nLim Trans Cwnd:   %u", sndCongRod->SndLimTransCwnd);
            wprintf(L"\nLim Time Cwnd:    %u", sndCongRod->SndLimTimeCwnd);
            wprintf(L"\nLim Bytes Cwnd:   %u", sndCongRod->SndLimBytesCwnd);
            wprintf(L"\nLim Trans Snd:    %u", sndCongRod->SndLimTransSnd);
            wprintf(L"\nLim Time Snd:     %u", sndCongRod->SndLimTimeSnd);
            wprintf(L"\nLim Bytes Snd:    %u", sndCongRod->SndLimBytesSnd);
            wprintf(L"\nSlow Start:       %u", sndCongRod->SlowStart);
            wprintf(L"\nCong Avoid:       %u", sndCongRod->CongAvoid);
            wprintf(L"\nOther Reductions: %u", sndCongRod->OtherReductions);
            wprintf(L"\nCur Cwnd:         %u", sndCongRod->CurCwnd);
            wprintf(L"\nMax Ss Cwnd:      %u", sndCongRod->MaxSsCwnd);
            wprintf(L"\nMax Ca Cwnd:      %u", sndCongRod->MaxCaCwnd);
            wprintf(L"\nCur Ss Thresh:    0x%x (%u)", sndCongRod->CurSsthresh,
                sndCongRod->CurSsthresh);
            wprintf(L"\nMax Ss Thresh:    0x%x (%u)", sndCongRod->MaxSsthresh,
                sndCongRod->MaxSsthresh);
            wprintf(L"\nMin Ss Thresh:    0x%x (%u)", sndCongRod->MinSsthresh,
                sndCongRod->MinSsthresh);
            wprintf(L"\nLim Cwnd:         0x%x (%u)", sndCongRos->LimCwnd,
                sndCongRos->LimCwnd);
            break;

        case TcpConnectionEstatsPath:
            pathRod = (PTCP_ESTATS_PATH_ROD_v0)rod;
            wprintf(L"\n\nPath");
            wprintf(L"\nFast Retran:         %u", pathRod->FastRetran);
            wprintf(L"\nTimeouts:            %u", pathRod->Timeouts);
            wprintf(L"\nSubsequent Timeouts: %u", pathRod->SubsequentTimeouts);
            wprintf(L"\nCur Timeout Count:   %u", pathRod->CurTimeoutCount);
            wprintf(L"\nAbrupt Timeouts:     %u", pathRod->AbruptTimeouts);
            wprintf(L"\nPkts Retrans:        %u", pathRod->PktsRetrans);
            wprintf(L"\nBytes Retrans:       %u", pathRod->BytesRetrans);
            wprintf(L"\nDup Acks In:         %u", pathRod->DupAcksIn);
            wprintf(L"\nSacksRcvd:           %u", pathRod->SacksRcvd);
            wprintf(L"\nSack Blocks Rcvd:    %u", pathRod->SackBlocksRcvd);
            wprintf(L"\nCong Signals:        %u", pathRod->CongSignals);
            wprintf(L"\nPre Cong Sum Cwnd:   %u", pathRod->PreCongSumCwnd);
            wprintf(L"\nPre Cong Sum Rtt:    %u", pathRod->PreCongSumRtt);
            wprintf(L"\nPost Cong Sum Rtt:   %u", pathRod->PostCongSumRtt);
            wprintf(L"\nPost Cong Count Rtt: %u", pathRod->PostCongCountRtt);
            wprintf(L"\nEcn Signals:         %u", pathRod->EcnSignals);
            wprintf(L"\nEce Rcvd:            %u", pathRod->EceRcvd);
            wprintf(L"\nSend Stall:          %u", pathRod->SendStall);
            wprintf(L"\nQuench Rcvd:         %u", pathRod->QuenchRcvd);
            wprintf(L"\nRetran Thresh:       %u", pathRod->RetranThresh);
            wprintf(L"\nSnd Dup Ack Episodes:  %u", pathRod->SndDupAckEpisodes);
            wprintf(L"\nSum Bytes Reordered: %u", pathRod->SumBytesReordered);
            wprintf(L"\nNon Recov Da:        %u", pathRod->NonRecovDa);
            wprintf(L"\nNon Recov Da Episodes: %u", pathRod->NonRecovDaEpisodes);
            wprintf(L"\nAck After Fr:        %u", pathRod->AckAfterFr);
            wprintf(L"\nDsack Dups:          %u", pathRod->DsackDups);
            wprintf(L"\nSample Rtt:          0x%x (%u)", pathRod->SampleRtt,
                pathRod->SampleRtt);
            wprintf(L"\nSmoothed Rtt:        %u", pathRod->SmoothedRtt);
            wprintf(L"\nRtt Var:             %u", pathRod->RttVar);
            wprintf(L"\nMax Rtt:             %u", pathRod->MaxRtt);
            wprintf(L"\nMin Rtt:             0x%x (%u)", pathRod->MinRtt,
                pathRod->MinRtt);
            wprintf(L"\nSum Rtt:             %u", pathRod->SumRtt);
            wprintf(L"\nCount Rtt:           %u", pathRod->CountRtt);
            wprintf(L"\nCur Rto:             %u", pathRod->CurRto);
            wprintf(L"\nMax Rto:             %u", pathRod->MaxRto);
            wprintf(L"\nMin Rto:             %u", pathRod->MinRto);
            wprintf(L"\nCur Mss:             %u", pathRod->CurMss);
            wprintf(L"\nMax Mss:             %u", pathRod->MaxMss);
            wprintf(L"\nMin Mss:             %u", pathRod->MinMss);
            wprintf(L"\nSpurious Rto:        %u", pathRod->SpuriousRtoDetections);
            break;

        case TcpConnectionEstatsSendBuff:
            sndBuffRod = (PTCP_ESTATS_SEND_BUFF_ROD_v0)rod;
            wprintf(L"\n\nSend Buff");
            wprintf(L"\nCur Retx Queue:   %u", sndBuffRod->CurRetxQueue);
            wprintf(L"\nMax Retx Queue:   %u", sndBuffRod->MaxRetxQueue);
            wprintf(L"\nCur App W Queue:  %u", sndBuffRod->CurAppWQueue);
            wprintf(L"\nMax App W Queue:  %u", sndBuffRod->MaxAppWQueue);
            break;

        case TcpConnectionEstatsRec:
            recRod = (PTCP_ESTATS_REC_ROD_v0)rod;
            wprintf(L"\n\nRec");
            wprintf(L"\nCur Rwin Sent:   0x%x (%u)", recRod->CurRwinSent,
                recRod->CurRwinSent);
            wprintf(L"\nMax Rwin Sent:   0x%x (%u)", recRod->MaxRwinSent,
                recRod->MaxRwinSent);
            wprintf(L"\nMin Rwin Sent:   0x%x (%u)", recRod->MinRwinSent,
                recRod->MinRwinSent);
            wprintf(L"\nLim Rwin:        0x%x (%u)", recRod->LimRwin,
                recRod->LimRwin);
            wprintf(L"\nDup Acks:        %u", recRod->DupAckEpisodes);
            wprintf(L"\nDup Acks Out:    %u", recRod->DupAcksOut);
            wprintf(L"\nCe Rcvd:         %u", recRod->CeRcvd);
            wprintf(L"\nEcn Send:        %u", recRod->EcnSent);
            wprintf(L"\nEcn Nonces Rcvd: %u", recRod->EcnNoncesRcvd);
            wprintf(L"\nCur Reasm Queue: %u", recRod->CurReasmQueue);
            wprintf(L"\nMax Reasm Queue: %u", recRod->MaxReasmQueue);
            wprintf(L"\nCur App R Queue: %u", recRod->CurAppRQueue);
            wprintf(L"\nMax App R Queue: %u", recRod->MaxAppRQueue);
            wprintf(L"\nWin Scale Sent:  0x%.2x", recRod->WinScaleSent);
            break;

        case TcpConnectionEstatsObsRec:
            obsRecRod = (PTCP_ESTATS_OBS_REC_ROD_v0)rod;
            wprintf(L"\n\nObs Rec");
            wprintf(L"\nCur Rwin Rcvd:   0x%x (%u)", obsRecRod->CurRwinRcvd,
                obsRecRod->CurRwinRcvd);
            wprintf(L"\nMax Rwin Rcvd:   0x%x (%u)", obsRecRod->MaxRwinRcvd,
                obsRecRod->MaxRwinRcvd);
            wprintf(L"\nMin Rwin Rcvd:   0x%x (%u)", obsRecRod->MinRwinRcvd,
                obsRecRod->MinRwinRcvd);
            wprintf(L"\nWin Scale Rcvd:  0x%x (%u)", obsRecRod->WinScaleRcvd,
                obsRecRod->WinScaleRcvd);
            break;

        case TcpConnectionEstatsBandwidth:
            bandwidthRod = (PTCP_ESTATS_BANDWIDTH_ROD_v0)rod;
            wprintf(L"\n\nBandwidth");
            wprintf(L"\nOutbound Bandwidth:   %lu",
                bandwidthRod->OutboundBandwidth);
            wprintf(L"\nInbound Bandwidth:    %lu", bandwidthRod->InboundBandwidth);
            wprintf(L"\nOutbound Instability: %lu",
                bandwidthRod->OutboundInstability);
            wprintf(L"\nInbound Instability:  %lu",
                bandwidthRod->InboundInstability);
            wprintf(L"\nOutbound Bandwidth Peaked: %s",
                bandwidthRod->OutboundBandwidthPeaked ? L"Yes" : L"No");
            wprintf(L"\nInbound Bandwidth Peaked:  %s",
                bandwidthRod->InboundBandwidthPeaked ? L"Yes" : L"No");
            break;

        case TcpConnectionEstatsFineRtt:
            fineRttRod = (PTCP_ESTATS_FINE_RTT_ROD_v0)rod;
            wprintf(L"\n\nFine RTT");
            wprintf(L"\nRtt Var: %u", fineRttRod->RttVar);
            wprintf(L"\nMax Rtt: %u", fineRttRod->MaxRtt);
            wprintf(L"\nMin Rtt: 0x%x (%u) ", fineRttRod->MinRtt,
                fineRttRod->MinRtt);
            wprintf(L"\nSum Rtt: %u", fineRttRod->SumRtt);
            break;

        default:
            wprintf(L"\nCannot get type %d", type);
            break;
        }
    }

    free(ros);
    free(rod);
}
出典・ライセンス: 上記「公式ドキュメント」の内容は Microsoft の Win32 API ドキュメント(MicrosoftDocs/sdk-api)を日本語に翻訳・改変したものです。© Microsoft Corporation. CC BY 4.0 で提供。
Microsoft 公式リファレンス: 英語 (en-us) · 日本語 (ja-jp) · 原文ソース (GitHub)

各言語での呼び出し定義

// IPHLPAPI.dll
#include <windows.h>

DWORD GetPerTcp6ConnectionEStats(
    MIB_TCP6ROW* Row,
    TCP_ESTATS_TYPE EstatsType,
    BYTE* Rw,   // optional
    DWORD RwVersion,
    DWORD RwSize,
    BYTE* Ros,   // optional
    DWORD RosVersion,
    DWORD RosSize,
    BYTE* Rod,   // optional
    DWORD RodVersion,
    DWORD RodSize
);
[DllImport("IPHLPAPI.dll", ExactSpelling = true)]
static extern uint GetPerTcp6ConnectionEStats(
    IntPtr Row,   // MIB_TCP6ROW*
    int EstatsType,   // TCP_ESTATS_TYPE
    IntPtr Rw,   // BYTE* optional, out
    uint RwVersion,   // DWORD
    uint RwSize,   // DWORD
    IntPtr Ros,   // BYTE* optional, out
    uint RosVersion,   // DWORD
    uint RosSize,   // DWORD
    IntPtr Rod,   // BYTE* optional, out
    uint RodVersion,   // DWORD
    uint RodSize   // DWORD
);
<DllImport("IPHLPAPI.dll", ExactSpelling:=True)>
Public Shared Function GetPerTcp6ConnectionEStats(
    Row As IntPtr,   ' MIB_TCP6ROW*
    EstatsType As Integer,   ' TCP_ESTATS_TYPE
    Rw As IntPtr,   ' BYTE* optional, out
    RwVersion As UInteger,   ' DWORD
    RwSize As UInteger,   ' DWORD
    Ros As IntPtr,   ' BYTE* optional, out
    RosVersion As UInteger,   ' DWORD
    RosSize As UInteger,   ' DWORD
    Rod As IntPtr,   ' BYTE* optional, out
    RodVersion As UInteger,   ' DWORD
    RodSize As UInteger   ' DWORD
) As UInteger
End Function
' Row : MIB_TCP6ROW*
' EstatsType : TCP_ESTATS_TYPE
' Rw : BYTE* optional, out
' RwVersion : DWORD
' RwSize : DWORD
' Ros : BYTE* optional, out
' RosVersion : DWORD
' RosSize : DWORD
' Rod : BYTE* optional, out
' RodVersion : DWORD
' RodSize : DWORD
Declare PtrSafe Function GetPerTcp6ConnectionEStats Lib "iphlpapi" ( _
    ByVal Row As LongPtr, _
    ByVal EstatsType As Long, _
    ByVal Rw As LongPtr, _
    ByVal RwVersion As Long, _
    ByVal RwSize As Long, _
    ByVal Ros As LongPtr, _
    ByVal RosVersion As Long, _
    ByVal RosSize As Long, _
    ByVal Rod As LongPtr, _
    ByVal RodVersion As Long, _
    ByVal RodSize As Long) As Long
' VBA7前提(PtrSafe)。32bit Office では LongPtr→Long。Integer=16bit / Long=32bit / LongLong=64bit。
import ctypes
from ctypes import wintypes

GetPerTcp6ConnectionEStats = ctypes.windll.iphlpapi.GetPerTcp6ConnectionEStats
GetPerTcp6ConnectionEStats.restype = wintypes.DWORD
GetPerTcp6ConnectionEStats.argtypes = [
    ctypes.c_void_p,  # Row : MIB_TCP6ROW*
    ctypes.c_int,  # EstatsType : TCP_ESTATS_TYPE
    ctypes.POINTER(ctypes.c_ubyte),  # Rw : BYTE* optional, out
    wintypes.DWORD,  # RwVersion : DWORD
    wintypes.DWORD,  # RwSize : DWORD
    ctypes.POINTER(ctypes.c_ubyte),  # Ros : BYTE* optional, out
    wintypes.DWORD,  # RosVersion : DWORD
    wintypes.DWORD,  # RosSize : DWORD
    ctypes.POINTER(ctypes.c_ubyte),  # Rod : BYTE* optional, out
    wintypes.DWORD,  # RodVersion : DWORD
    wintypes.DWORD,  # RodSize : DWORD
]
require 'fiddle'
require 'fiddle/import'

lib = Fiddle.dlopen('IPHLPAPI.dll')
GetPerTcp6ConnectionEStats = Fiddle::Function.new(
  lib['GetPerTcp6ConnectionEStats'],
  [
    Fiddle::TYPE_VOIDP,  # Row : MIB_TCP6ROW*
    Fiddle::TYPE_INT,  # EstatsType : TCP_ESTATS_TYPE
    Fiddle::TYPE_VOIDP,  # Rw : BYTE* optional, out
    -Fiddle::TYPE_INT,  # RwVersion : DWORD
    -Fiddle::TYPE_INT,  # RwSize : DWORD
    Fiddle::TYPE_VOIDP,  # Ros : BYTE* optional, out
    -Fiddle::TYPE_INT,  # RosVersion : DWORD
    -Fiddle::TYPE_INT,  # RosSize : DWORD
    Fiddle::TYPE_VOIDP,  # Rod : BYTE* optional, out
    -Fiddle::TYPE_INT,  # RodVersion : DWORD
    -Fiddle::TYPE_INT,  # RodSize : DWORD
  ],
  -Fiddle::TYPE_INT)
#[link(name = "iphlpapi")]
extern "system" {
    fn GetPerTcp6ConnectionEStats(
        Row: *mut MIB_TCP6ROW,  // MIB_TCP6ROW*
        EstatsType: i32,  // TCP_ESTATS_TYPE
        Rw: *mut u8,  // BYTE* optional, out
        RwVersion: u32,  // DWORD
        RwSize: u32,  // DWORD
        Ros: *mut u8,  // BYTE* optional, out
        RosVersion: u32,  // DWORD
        RosSize: u32,  // DWORD
        Rod: *mut u8,  // BYTE* optional, out
        RodVersion: u32,  // DWORD
        RodSize: u32  // DWORD
    ) -> u32;
}
// crates: windows-sys provides ready-made bindings for this API.
$sig = @"
[DllImport("IPHLPAPI.dll")]
public static extern uint GetPerTcp6ConnectionEStats(IntPtr Row, int EstatsType, IntPtr Rw, uint RwVersion, uint RwSize, IntPtr Ros, uint RosVersion, uint RosSize, IntPtr Rod, uint RodVersion, uint RodSize);
"@
$api = Add-Type -MemberDefinition $sig -Name 'IPHLPAPI_GetPerTcp6ConnectionEStats' -Namespace Win32 -PassThru
# $api::GetPerTcp6ConnectionEStats(Row, EstatsType, Rw, RwVersion, RwSize, Ros, RosVersion, RosSize, Rod, RodVersion, RodSize)
#uselib "IPHLPAPI.dll"
#func global GetPerTcp6ConnectionEStats "GetPerTcp6ConnectionEStats" sptr, sptr, sptr, sptr, sptr, sptr, sptr, sptr, sptr, sptr, sptr
; GetPerTcp6ConnectionEStats varptr(Row), EstatsType, varptr(Rw), RwVersion, RwSize, varptr(Ros), RosVersion, RosSize, varptr(Rod), RodVersion, RodSize   ; 戻り値は stat
; Row : MIB_TCP6ROW* -> "sptr"
; EstatsType : TCP_ESTATS_TYPE -> "sptr"
; Rw : BYTE* optional, out -> "sptr"
; RwVersion : DWORD -> "sptr"
; RwSize : DWORD -> "sptr"
; Ros : BYTE* optional, out -> "sptr"
; RosVersion : DWORD -> "sptr"
; RosSize : DWORD -> "sptr"
; Rod : BYTE* optional, out -> "sptr"
; RodVersion : DWORD -> "sptr"
; RodSize : DWORD -> "sptr"
; ※HSP3.7は #func のため戻り値はシステム変数 stat に格納されます。
出力引数:
#uselib "IPHLPAPI.dll"
#cfunc global GetPerTcp6ConnectionEStats "GetPerTcp6ConnectionEStats" var, int, var, int, int, var, int, int, var, int, int
; res = GetPerTcp6ConnectionEStats(Row, EstatsType, Rw, RwVersion, RwSize, Ros, RosVersion, RosSize, Rod, RodVersion, RodSize)
; Row : MIB_TCP6ROW* -> "var"
; EstatsType : TCP_ESTATS_TYPE -> "int"
; Rw : BYTE* optional, out -> "var"
; RwVersion : DWORD -> "int"
; RwSize : DWORD -> "int"
; Ros : BYTE* optional, out -> "var"
; RosVersion : DWORD -> "int"
; RosSize : DWORD -> "int"
; Rod : BYTE* optional, out -> "var"
; RodVersion : DWORD -> "int"
; RodSize : DWORD -> "int"
; ※出力/バッファ引数は var 方式(変数を直接渡す)。varptr 方式にも切替可。
出力引数:
; DWORD GetPerTcp6ConnectionEStats(MIB_TCP6ROW* Row, TCP_ESTATS_TYPE EstatsType, BYTE* Rw, DWORD RwVersion, DWORD RwSize, BYTE* Ros, DWORD RosVersion, DWORD RosSize, BYTE* Rod, DWORD RodVersion, DWORD RodSize)
#uselib "IPHLPAPI.dll"
#cfunc global GetPerTcp6ConnectionEStats "GetPerTcp6ConnectionEStats" var, int, var, int, int, var, int, int, var, int, int
; res = GetPerTcp6ConnectionEStats(Row, EstatsType, Rw, RwVersion, RwSize, Ros, RosVersion, RosSize, Rod, RodVersion, RodSize)
; Row : MIB_TCP6ROW* -> "var"
; EstatsType : TCP_ESTATS_TYPE -> "int"
; Rw : BYTE* optional, out -> "var"
; RwVersion : DWORD -> "int"
; RwSize : DWORD -> "int"
; Ros : BYTE* optional, out -> "var"
; RosVersion : DWORD -> "int"
; RosSize : DWORD -> "int"
; Rod : BYTE* optional, out -> "var"
; RodVersion : DWORD -> "int"
; RodSize : DWORD -> "int"
; ※出力/バッファ引数は var 方式(変数を直接渡す)。varptr 方式にも切替可。
import (
	"golang.org/x/sys/windows"
	"unsafe"
)

var (
	iphlpapi = windows.NewLazySystemDLL("IPHLPAPI.dll")
	procGetPerTcp6ConnectionEStats = iphlpapi.NewProc("GetPerTcp6ConnectionEStats")
)

// Row (MIB_TCP6ROW*), EstatsType (TCP_ESTATS_TYPE), Rw (BYTE* optional, out), RwVersion (DWORD), RwSize (DWORD), Ros (BYTE* optional, out), RosVersion (DWORD), RosSize (DWORD), Rod (BYTE* optional, out), RodVersion (DWORD), RodSize (DWORD)
r1, _, err := procGetPerTcp6ConnectionEStats.Call(
	uintptr(Row),
	uintptr(EstatsType),
	uintptr(Rw),
	uintptr(RwVersion),
	uintptr(RwSize),
	uintptr(Ros),
	uintptr(RosVersion),
	uintptr(RosSize),
	uintptr(Rod),
	uintptr(RodVersion),
	uintptr(RodSize),
)
_ = err  // syscall.Errno (valid when the call sets last-error)
_ = r1   // DWORD
function GetPerTcp6ConnectionEStats(
  Row: Pointer;   // MIB_TCP6ROW*
  EstatsType: Integer;   // TCP_ESTATS_TYPE
  Rw: Pointer;   // BYTE* optional, out
  RwVersion: DWORD;   // DWORD
  RwSize: DWORD;   // DWORD
  Ros: Pointer;   // BYTE* optional, out
  RosVersion: DWORD;   // DWORD
  RosSize: DWORD;   // DWORD
  Rod: Pointer;   // BYTE* optional, out
  RodVersion: DWORD;   // DWORD
  RodSize: DWORD   // DWORD
): DWORD; stdcall;
  external 'IPHLPAPI.dll' name 'GetPerTcp6ConnectionEStats';
result := DllCall("IPHLPAPI\GetPerTcp6ConnectionEStats"
    , "Ptr", Row   ; MIB_TCP6ROW*
    , "Int", EstatsType   ; TCP_ESTATS_TYPE
    , "Ptr", Rw   ; BYTE* optional, out
    , "UInt", RwVersion   ; DWORD
    , "UInt", RwSize   ; DWORD
    , "Ptr", Ros   ; BYTE* optional, out
    , "UInt", RosVersion   ; DWORD
    , "UInt", RosSize   ; DWORD
    , "Ptr", Rod   ; BYTE* optional, out
    , "UInt", RodVersion   ; DWORD
    , "UInt", RodSize   ; DWORD
    , "UInt")   ; return: DWORD
●GetPerTcp6ConnectionEStats(Row, EstatsType, Rw, RwVersion, RwSize, Ros, RosVersion, RosSize, Rod, RodVersion, RodSize) = DLL("IPHLPAPI.dll", "dword GetPerTcp6ConnectionEStats(void*, int, void*, dword, dword, void*, dword, dword, void*, dword, dword)")
# 呼び出し: GetPerTcp6ConnectionEStats(Row, EstatsType, Rw, RwVersion, RwSize, Ros, RosVersion, RosSize, Rod, RodVersion, RodSize)
# Row : MIB_TCP6ROW* -> "void*"
# EstatsType : TCP_ESTATS_TYPE -> "int"
# Rw : BYTE* optional, out -> "void*"
# RwVersion : DWORD -> "dword"
# RwSize : DWORD -> "dword"
# Ros : BYTE* optional, out -> "void*"
# RosVersion : DWORD -> "dword"
# RosSize : DWORD -> "dword"
# Rod : BYTE* optional, out -> "void*"
# RodVersion : DWORD -> "dword"
# RodSize : DWORD -> "dword"
# なでしこ1は32bit・ANSI(Shift_JIS)。文字列=char*(ANSI)、ポインタ/ハンドル=void*(4byte)。
const std = @import("std");

extern "iphlpapi" fn GetPerTcp6ConnectionEStats(
    Row: [*c]MIB_TCP6ROW, // MIB_TCP6ROW*
    EstatsType: i32, // TCP_ESTATS_TYPE
    Rw: [*c]u8, // BYTE* optional, out
    RwVersion: u32, // DWORD
    RwSize: u32, // DWORD
    Ros: [*c]u8, // BYTE* optional, out
    RosVersion: u32, // DWORD
    RosSize: u32, // DWORD
    Rod: [*c]u8, // BYTE* optional, out
    RodVersion: u32, // DWORD
    RodSize: u32 // DWORD
) callconv(std.os.windows.WINAPI) u32;
proc GetPerTcp6ConnectionEStats(
    Row: ptr MIB_TCP6ROW,  # MIB_TCP6ROW*
    EstatsType: int32,  # TCP_ESTATS_TYPE
    Rw: ptr uint8,  # BYTE* optional, out
    RwVersion: uint32,  # DWORD
    RwSize: uint32,  # DWORD
    Ros: ptr uint8,  # BYTE* optional, out
    RosVersion: uint32,  # DWORD
    RosSize: uint32,  # DWORD
    Rod: ptr uint8,  # BYTE* optional, out
    RodVersion: uint32,  # DWORD
    RodSize: uint32  # DWORD
): uint32 {.importc: "GetPerTcp6ConnectionEStats", stdcall, dynlib: "IPHLPAPI.dll".}
pragma(lib, "iphlpapi");
extern(Windows)
uint GetPerTcp6ConnectionEStats(
    MIB_TCP6ROW* Row,   // MIB_TCP6ROW*
    int EstatsType,   // TCP_ESTATS_TYPE
    ubyte* Rw,   // BYTE* optional, out
    uint RwVersion,   // DWORD
    uint RwSize,   // DWORD
    ubyte* Ros,   // BYTE* optional, out
    uint RosVersion,   // DWORD
    uint RosSize,   // DWORD
    ubyte* Rod,   // BYTE* optional, out
    uint RodVersion,   // DWORD
    uint RodSize   // DWORD
);
ccall((:GetPerTcp6ConnectionEStats, "IPHLPAPI.dll"), stdcall, UInt32,
      (Ptr{MIB_TCP6ROW}, Int32, Ptr{UInt8}, UInt32, UInt32, Ptr{UInt8}, UInt32, UInt32, Ptr{UInt8}, UInt32, UInt32),
      Row, EstatsType, Rw, RwVersion, RwSize, Ros, RosVersion, RosSize, Rod, RodVersion, RodSize)
# Row : MIB_TCP6ROW* -> Ptr{MIB_TCP6ROW}
# EstatsType : TCP_ESTATS_TYPE -> Int32
# Rw : BYTE* optional, out -> Ptr{UInt8}
# RwVersion : DWORD -> UInt32
# RwSize : DWORD -> UInt32
# Ros : BYTE* optional, out -> Ptr{UInt8}
# RosVersion : DWORD -> UInt32
# RosSize : DWORD -> UInt32
# Rod : BYTE* optional, out -> Ptr{UInt8}
# RodVersion : DWORD -> UInt32
# RodSize : DWORD -> UInt32
# stdcall は 32bit のみ意味を持つ(x64 では無視)。
local ffi = require("ffi")
ffi.cdef[[
uint32_t GetPerTcp6ConnectionEStats(
    void* Row,
    int32_t EstatsType,
    uint8_t* Rw,
    uint32_t RwVersion,
    uint32_t RwSize,
    uint8_t* Ros,
    uint32_t RosVersion,
    uint32_t RosSize,
    uint8_t* Rod,
    uint32_t RodVersion,
    uint32_t RodSize);
]]
local iphlpapi = ffi.load("iphlpapi")
-- iphlpapi.GetPerTcp6ConnectionEStats(Row, EstatsType, Rw, RwVersion, RwSize, Ros, RosVersion, RosSize, Rod, RodVersion, RodSize)
-- Row : MIB_TCP6ROW*
-- EstatsType : TCP_ESTATS_TYPE
-- Rw : BYTE* optional, out
-- RwVersion : DWORD
-- RwSize : DWORD
-- Ros : BYTE* optional, out
-- RosVersion : DWORD
-- RosSize : DWORD
-- Rod : BYTE* optional, out
-- RodVersion : DWORD
-- RodSize : DWORD
-- 構造体/GUIDへのポインタは cdef が通るよう void* で表記(実型は各引数コメント参照)。値渡し構造体・enum は対応する typedef を cdef に追加すること。
const koffi = require('koffi');
const lib = koffi.load('IPHLPAPI.dll');
const GetPerTcp6ConnectionEStats = lib.func('__stdcall', 'GetPerTcp6ConnectionEStats', 'uint32_t', ['void *', 'int32_t', 'uint8_t *', 'uint32_t', 'uint32_t', 'uint8_t *', 'uint32_t', 'uint32_t', 'uint8_t *', 'uint32_t', 'uint32_t']);
// GetPerTcp6ConnectionEStats(Row, EstatsType, Rw, RwVersion, RwSize, Ros, RosVersion, RosSize, Rod, RodVersion, RodSize)
// Row : MIB_TCP6ROW* -> 'void *'
// EstatsType : TCP_ESTATS_TYPE -> 'int32_t'
// Rw : BYTE* optional, out -> 'uint8_t *'
// RwVersion : DWORD -> 'uint32_t'
// RwSize : DWORD -> 'uint32_t'
// Ros : BYTE* optional, out -> 'uint8_t *'
// RosVersion : DWORD -> 'uint32_t'
// RosSize : DWORD -> 'uint32_t'
// Rod : BYTE* optional, out -> 'uint8_t *'
// RodVersion : DWORD -> 'uint32_t'
// RodSize : DWORD -> 'uint32_t'
// 出力ポインタは koffi.out(...) で包む。構造体は koffi.struct で定義。
const lib = Deno.dlopen("IPHLPAPI.dll", {
  GetPerTcp6ConnectionEStats: { parameters: ["pointer", "i32", "pointer", "u32", "u32", "pointer", "u32", "u32", "pointer", "u32", "u32"], result: "u32" },
});
// lib.symbols.GetPerTcp6ConnectionEStats(Row, EstatsType, Rw, RwVersion, RwSize, Ros, RosVersion, RosSize, Rod, RodVersion, RodSize)
// Row : MIB_TCP6ROW* -> "pointer"
// EstatsType : TCP_ESTATS_TYPE -> "i32"
// Rw : BYTE* optional, out -> "pointer"
// RwVersion : DWORD -> "u32"
// RwSize : DWORD -> "u32"
// Ros : BYTE* optional, out -> "pointer"
// RosVersion : DWORD -> "u32"
// RosSize : DWORD -> "u32"
// Rod : BYTE* optional, out -> "pointer"
// RodVersion : DWORD -> "u32"
// RodSize : DWORD -> "u32"
// 文字列引数は "buffer"(NUL 終端のバイト列を Uint8Array で渡す)。
// 値渡し構造体は { struct: [ ...field types... ] } を使用。
<?php
$ffi = FFI::cdef(<<<C
uint32_t GetPerTcp6ConnectionEStats(
    void* Row,
    int32_t EstatsType,
    uint8_t* Rw,
    uint32_t RwVersion,
    uint32_t RwSize,
    uint8_t* Ros,
    uint32_t RosVersion,
    uint32_t RosSize,
    uint8_t* Rod,
    uint32_t RodVersion,
    uint32_t RodSize);
C, "IPHLPAPI.dll");
// $ffi->GetPerTcp6ConnectionEStats(Row, EstatsType, Rw, RwVersion, RwSize, Ros, RosVersion, RosSize, Rod, RodVersion, RodSize);
// Row : MIB_TCP6ROW*
// EstatsType : TCP_ESTATS_TYPE
// Rw : BYTE* optional, out
// RwVersion : DWORD
// RwSize : DWORD
// Ros : BYTE* optional, out
// RosVersion : DWORD
// RosSize : DWORD
// Rod : BYTE* optional, out
// RodVersion : DWORD
// RodSize : DWORD
// 構造体/GUIDへのポインタは cdef が通るよう void* で表記(実型は各引数コメント参照)。値渡し構造体・enum は対応する typedef を cdef に追加すること。
// WINAPI(stdcall): x64 では呼出規約が統一されるため問題なし。x86 では __stdcall 対応のラッパが必要な場合あり。
import com.sun.jna.*;
import com.sun.jna.ptr.*;
import com.sun.jna.win32.StdCallLibrary;
import com.sun.jna.win32.W32APIOptions;

public interface Iphlpapi extends StdCallLibrary {
    Iphlpapi INSTANCE = Native.load("iphlpapi", Iphlpapi.class);
    int GetPerTcp6ConnectionEStats(
        Pointer Row,   // MIB_TCP6ROW*
        int EstatsType,   // TCP_ESTATS_TYPE
        byte[] Rw,   // BYTE* optional, out
        int RwVersion,   // DWORD
        int RwSize,   // DWORD
        byte[] Ros,   // BYTE* optional, out
        int RosVersion,   // DWORD
        int RosSize,   // DWORD
        byte[] Rod,   // BYTE* optional, out
        int RodVersion,   // DWORD
        int RodSize   // DWORD
    );
}
@[Link("iphlpapi")]
lib LibIPHLPAPI
  fun GetPerTcp6ConnectionEStats = GetPerTcp6ConnectionEStats(
    Row : MIB_TCP6ROW*,   # MIB_TCP6ROW*
    EstatsType : Int32,   # TCP_ESTATS_TYPE
    Rw : UInt8*,   # BYTE* optional, out
    RwVersion : UInt32,   # DWORD
    RwSize : UInt32,   # DWORD
    Ros : UInt8*,   # BYTE* optional, out
    RosVersion : UInt32,   # DWORD
    RosSize : UInt32,   # DWORD
    Rod : UInt8*,   # BYTE* optional, out
    RodVersion : UInt32,   # DWORD
    RodSize : UInt32   # DWORD
  ) : UInt32
end
# 構造体/GUID/enum は lib 内に対応する型定義が必要。
# 呼出規約: x64 は規約統一のため OK。x86(32bit)は WINAPI=stdcall だが Crystal の fun に stdcall 付与構文がなく非対応。
import 'dart:ffi';
import 'package:ffi/ffi.dart';

typedef GetPerTcp6ConnectionEStatsNative = Uint32 Function(Pointer<Void>, Int32, Pointer<Uint8>, Uint32, Uint32, Pointer<Uint8>, Uint32, Uint32, Pointer<Uint8>, Uint32, Uint32);
typedef GetPerTcp6ConnectionEStatsDart = int Function(Pointer<Void>, int, Pointer<Uint8>, int, int, Pointer<Uint8>, int, int, Pointer<Uint8>, int, int);
final GetPerTcp6ConnectionEStats = DynamicLibrary.open('IPHLPAPI.dll')
    .lookupFunction<GetPerTcp6ConnectionEStatsNative, GetPerTcp6ConnectionEStatsDart>('GetPerTcp6ConnectionEStats');
// Row : MIB_TCP6ROW* -> Pointer<Void>
// EstatsType : TCP_ESTATS_TYPE -> Int32
// Rw : BYTE* optional, out -> Pointer<Uint8>
// RwVersion : DWORD -> Uint32
// RwSize : DWORD -> Uint32
// Ros : BYTE* optional, out -> Pointer<Uint8>
// RosVersion : DWORD -> Uint32
// RosSize : DWORD -> Uint32
// Rod : BYTE* optional, out -> Pointer<Uint8>
// RodVersion : DWORD -> Uint32
// RodSize : DWORD -> Uint32
// 文字列は package:ffi の "...".toNativeUtf16()/toNativeUtf8() で変換。
{$mode objfpc}{$H+}
function GetPerTcp6ConnectionEStats(
  Row: Pointer;   // MIB_TCP6ROW*
  EstatsType: Integer;   // TCP_ESTATS_TYPE
  Rw: Pointer;   // BYTE* optional, out
  RwVersion: DWORD;   // DWORD
  RwSize: DWORD;   // DWORD
  Ros: Pointer;   // BYTE* optional, out
  RosVersion: DWORD;   // DWORD
  RosSize: DWORD;   // DWORD
  Rod: Pointer;   // BYTE* optional, out
  RodVersion: DWORD;   // DWORD
  RodSize: DWORD   // DWORD
): DWORD; stdcall;
  external 'IPHLPAPI.dll' name 'GetPerTcp6ConnectionEStats';
import Foreign
import Foreign.C.Types
import Foreign.C.String

foreign import stdcall safe "GetPerTcp6ConnectionEStats"
  c_GetPerTcp6ConnectionEStats :: Ptr () -> Int32 -> Ptr Word8 -> Word32 -> Word32 -> Ptr Word8 -> Word32 -> Word32 -> Ptr Word8 -> Word32 -> Word32 -> IO Word32
-- Row : MIB_TCP6ROW* -> Ptr ()
-- EstatsType : TCP_ESTATS_TYPE -> Int32
-- Rw : BYTE* optional, out -> Ptr Word8
-- RwVersion : DWORD -> Word32
-- RwSize : DWORD -> Word32
-- Ros : BYTE* optional, out -> Ptr Word8
-- RosVersion : DWORD -> Word32
-- RosSize : DWORD -> Word32
-- Rod : BYTE* optional, out -> Ptr Word8
-- RodVersion : DWORD -> Word32
-- RodSize : DWORD -> Word32
-- 要 GHC(Windows)。stdcall は x64 では ccall として扱われる。ブロックする API は safe 呼び出し推奨。
open Ctypes
open Foreign

let getpertcp6connectionestats =
  foreign "GetPerTcp6ConnectionEStats"
    ((ptr void) @-> int32_t @-> (ptr uint8_t) @-> uint32_t @-> uint32_t @-> (ptr uint8_t) @-> uint32_t @-> uint32_t @-> (ptr uint8_t) @-> uint32_t @-> uint32_t @-> returning uint32_t)
(* Row : MIB_TCP6ROW* -> (ptr void) *)
(* EstatsType : TCP_ESTATS_TYPE -> int32_t *)
(* Rw : BYTE* optional, out -> (ptr uint8_t) *)
(* RwVersion : DWORD -> uint32_t *)
(* RwSize : DWORD -> uint32_t *)
(* Ros : BYTE* optional, out -> (ptr uint8_t) *)
(* RosVersion : DWORD -> uint32_t *)
(* RosSize : DWORD -> uint32_t *)
(* Rod : BYTE* optional, out -> (ptr uint8_t) *)
(* RodVersion : DWORD -> uint32_t *)
(* RodSize : DWORD -> uint32_t *)
(* foreign は cdecl 前提。x64 Windows では WINAPI と一致。構造体は ctypes structure を定義のこと。 *)
(cffi:define-foreign-library iphlpapi (t "IPHLPAPI.dll"))
(cffi:use-foreign-library iphlpapi)

(cffi:defcfun ("GetPerTcp6ConnectionEStats" get-per-tcp6-connection-estats :convention :stdcall) :uint32
  (row :pointer)   ; MIB_TCP6ROW*
  (estats-type :int32)   ; TCP_ESTATS_TYPE
  (rw :pointer)   ; BYTE* optional, out
  (rw-version :uint32)   ; DWORD
  (rw-size :uint32)   ; DWORD
  (ros :pointer)   ; BYTE* optional, out
  (ros-version :uint32)   ; DWORD
  (ros-size :uint32)   ; DWORD
  (rod :pointer)   ; BYTE* optional, out
  (rod-version :uint32)   ; DWORD
  (rod-size :uint32))   ; DWORD
; isize/usize(INT_PTR/SIZE_T)は x64 前提で :int64/:uint64。x86 では :int32/:uint32。
use Win32::API;
my $GetPerTcp6ConnectionEStats = Win32::API::More->new('IPHLPAPI',
    'DWORD GetPerTcp6ConnectionEStats(LPVOID Row, int EstatsType, LPVOID Rw, DWORD RwVersion, DWORD RwSize, LPVOID Ros, DWORD RosVersion, DWORD RosSize, LPVOID Rod, DWORD RodVersion, DWORD RodSize)');
# my $ret = $GetPerTcp6ConnectionEStats->Call($Row, $EstatsType, $Rw, $RwVersion, $RwSize, $Ros, $RosVersion, $RosSize, $Rod, $RodVersion, $RodSize);
# Row : MIB_TCP6ROW* -> LPVOID
# EstatsType : TCP_ESTATS_TYPE -> int
# Rw : BYTE* optional, out -> LPVOID
# RwVersion : DWORD -> DWORD
# RwSize : DWORD -> DWORD
# Ros : BYTE* optional, out -> LPVOID
# RosVersion : DWORD -> DWORD
# RosSize : DWORD -> DWORD
# Rod : BYTE* optional, out -> LPVOID
# RodVersion : DWORD -> DWORD
# RodSize : DWORD -> DWORD
# 値渡し構造体は pack() した文字列、または Win32::API::Struct を使用。

関連項目

公式の関連項目
使用する型