[此控制代码可能在将来的 Windows 版本中更改或不可用。 使用 Internet 协议帮助程序 API 而不是此控制代码。]
从 TCP/IP 驱动程序检索信息。
若要执行 IOCTL_TCP_QUERY_INFORMATION_EX 操作,请使用以下参数调用 DeviceIoControl 函数。
BOOL DeviceIoControl(
  (HANDLE) hDevice,                  // Open handle to the TCP driver
  IOCTL_TCP_QUERY_INFORMATION_EX,    // dwIoControlCode
  NULL,                              // lpInBuffer (the output buffer is used for input too)
  0,                                 // nInBufferSize
  (LPVOID) lpOutBuffer,              // Pointer to the output buffer
  (DWORD) nOutBufferSize,            // Size of the output buffer
  (LPDWORD) lpBytesReturned,         // Number of bytes returned (if called synchronously)
  (LPOVERLAPPED) lpOverlapped        // OVERLAPPED structure (if called asynchronously)
);
言论
若要使用 IOCTL_TCP_QUERY_INFORMATION_EX,应熟悉 Windows 驱动程序开发,如 Windows 驱动程序工具包(WDK)中所述,特别是传输驱动程序接口(TDI)驱动程序。
| 函件 | 代表 | 评论 | 
|---|---|---|
| “AT” | 地址转换 | 地址解析,如 ARP 提供的地址解析协议。 | 
| “NL” | 网络层 | 与开放系统互连(OSI)参考模型一样。 | 
| “TL” | 传输层 | 与 OSI 参考模型一样。 | 
| “CL” | Connection-Less | 基于广播数据包的无连接协议。 | 
| “CO” | 连接 | 基于定向数据包的连接协议。 | 
| “ER” | 回显请求/回复 | Ping 用于测试 TCP/IP 连接的数据包类型。 | 
| “IF” | 接口 | SNMP 中使用的意义上的接口。 | 
- 枚举 TDI 实体。
 
若要检索标识计算机上的所有 TCP 实体的 TDIEntityID 结构的数组,请将输入结构的 ID.toi_entity.tei_entity 成员设置为 GENERIC_ENTITY。 然后,必须将 ID.toi_class 设置为 INFO_CLASS_GENERIC,ID.toi_type 必须设置为 INFO_TYPE_PROVIDER,并且必须将 ID.toi_id 设置为 ENTITY_LIST_ID,否则操作将失败并出现TDI_INVALID_PARAMETER错误代码。 请求列表时,将忽略输入结构的 上下文 成员。 在本例中,输出是 TDIEntityID 结构的数组。 下面的第一个代码示例中的 GetEntityArray 函数演示如何检索此类数组。
- 获取有关特定 TDI 实体的类型信息。
 
如果输入结构的 ID.toi_entity 成员标识特定实体(如上述枚举请求返回的 TDIEntityID 结构),则将 ID.toi_class 设置为 INFO_CLASS_GENERIC,将 ID.toi_type 设置为 INFO_TYPE_PROVIDER,ID.toi_idENTITY_TYPE_ID 导致一个或多个标志值成为返回到由 lpOutBuffer 参数指向的 无符号长。 这些标志值标识指定实体的类型。 再次忽略输入结构的 上下文 成员。
下表显示了可返回的可能类型标志值。
| 旗 | 意义 | 
|---|---|
| AT_ARP | 实体实现 ARP(地址解析协议)。 | 
| AT_NULL | 实体不进行地址转换。 | 
| CL_NL_IP | 实体在网络层上实现 IP(Internet 协议),无连接。 | 
| CL_NL_IPX | 实体实现 IPX(Internetwork Packet Exchange 协议),在网络层上无连接。 | 
| CL_TL_NBF | 实体实现 NBF (NetBEUI 帧协议),在传输层上无连接。 | 
| CL_TL_UDP | 实体在传输层上实现 UDP(用户数据报协议)无连接。 | 
| CO_TL_NBF | 实体在传输层上实现 NBF (NetBEUI Frame 协议) 定向数据包。 | 
| CO_TL_SPP | 实体在传输层上实现 SPP(排序数据包协议),定向数据包。 | 
| CO_TL_SPX | 实体实现 SPX(序列化数据包交换协议),传输层上的定向数据包。 | 
| CO_TL_TCP | 实体在传输层上实现 TCP(传输控制协议)定向数据包。 | 
| ER_ICMP | 实体为回显请求/回复实现 ICMP (Internet 控制消息协议)。 | 
| IF_GENERIC | 实体实现泛型接口。 | 
| IF_MIB | 实体实现具有 SNMP MIB-II 支持的接口。 | 
- 获取有关接口实体的 MIB-II 信息。
 
如果实体类型IF_MIB,则可以将 MIB 请求发送到该请求,从而返回 IFEntry 结构。 将输入结构的 ID.toi_entity 成员设置为标识实体、要 INFO_CLASS_PROTOCOL的 ID.toi_class、要 INFO_TYPE_PROVIDER的 ID.toi_type,将 ID.toi_id 设置为 IF_MIB_STATS_ID。
请注意,由于 IFEntry 是可变长度结构,因此输出缓冲区的分配不仅仅是“sizeof(IFEntry)”,而应分配为“sizeof(IFEntry)+MAX_ADAPTER_DESCRIPTION_LENGTH + 1”。
- 获取有关特定 IP 实体的 MIB-II 信息。
 
还可以从 IP 实体(类型为 CL_NL_ENTITY)检索 MIB 信息,方法是将 ID.toi_entity 成员设置为标识实体、要 INFO_CLASS_PROTOCOL的 ID.toi_class、要 INFO_TYPE_PROVIDER的 ID.toi_type 以及要 IP_MIB_STATS_ID的 ID.toi_id。 在这种情况下,将返回 IPSNMPInfo 结构,输出缓冲区可以分配给“sizeof(IPSNMPInfo)”。
- 获取有关特定 IP 实体的地址信息。
 
如果为特定 IP 实体返回的 IPSNMPInfo 结构的 ipsi_numaddr 成员为非零,则可以通过将 ID.toi_entity 成员设置为标识实体、ID.toi_classINFO_CLASS_PROTOCOLID.toi_typeINFO_TYPE_PROVIDER来检索 IPAddrEntry 结构的数组。 和 IP_MIB_ADDRTABLE_ENTRY_IDID.toi_id。 在这种情况下,应分配输出缓冲区以保存大小数组:
sizeof(IPAddrEntry) * pIpSnmpInfoReturned->ipsi_numaddr
- 获取有关特定 IP 地址的接口信息。
 
通过将 ID.toi_entity 成员集保留为标识 IP ID.toi_class 实体、设置为 INFO_CLASS_PROTOCOL的 ID.toi_type 设置为 INFO_TYPE_PROVIDER,可以检索在上面 IPAddrEntry 数组中返回的给定 IP 地址的更多接口信息。 然后将 ID.toi_id 设置为 IP_INTFC_INFO_ID,并将 TCP_REQUEST_QUERY_INFORMATION_EX 结构的 上下文 成员设置为相关 IPv4 或 IPv6 地址。
分配足够大的输出缓冲区以包含 sizeof(IPINTERFACEINFO) + MAX_PHYSADDR_SIZE。
返回时,输出缓冲区包含填充 IPInterfaceInfo 结构。
例子
以下示例演示如何获取当前计算机上的 TCP 适配器上存在的实体的列表。
#define  UNICODE
#define  _WIN32_WINNT  0x0500
#include <stdio.h>
#include <windows.h>
#include <iptypes.h>
#include "winternl.h"
#include "tdiinfo.h"
#include "tdistat.h"
#include "tcpioctl.h"
/*  Function:              GetTCPHandle
    Description:
      Opens a handle to the TCP driver
    Parameters:
      pTCPDriverHandle --  Pointer to a handle variable.
    Return Value (DWORD):  Returns TRUE if successful, and places 
                           a valid handle to the TCP driver in the
                           handle pointed to by pTCPDriverHandle, or
                           returns FALSE otherwise, and sets the
                           handle to INVALID_HANDLE_VALUE.
*/
DWORD GetTCPHandle( PHANDLE pTCPDriverHandle )
{
#define FILE_OPEN_IF                    0x00000003
#define FILE_SYNCHRONOUS_IO_NONALERT    0x00000020
#define OBJ_CASE_INSENSITIVE            0x00000040L
typedef NTSTATUS (NTAPI *P_NT_CREATE_FILE)(
    OUT PHANDLE              FileHandle,
    IN  ACCESS_MASK          DesiredAccess,
    IN  POBJECT_ATTRIBUTES   ObjectAttributes,
    OUT PIO_STATUS_BLOCK     IoStatusBlock,
    IN  PLARGE_INTEGER       AllocationSize OPTIONAL,
    IN  ULONG                FileAttributes,
    IN  ULONG                ShareAccess,
    IN  ULONG                CreateDisposition,
    IN  ULONG                CreateOptions,
    IN  PVOID                EaBuffer OPTIONAL,
    IN  ULONG                EaLength );
  HINSTANCE hNtDLL;
  P_NT_CREATE_FILE pNtCreateFile;
  NTSTATUS rVal;
  WCHAR TCPDriverName[] = DD_TCP_DEVICE_NAME;
  OBJECT_ATTRIBUTES  objectAttributes;
  IO_STATUS_BLOCK    ioStatusBlock;
  UNICODE_STRING     UnicodeStr;
  *pTCPDriverHandle = INVALID_HANDLE_VALUE;
  if( ( hNtDLL = LoadLibrary( L"ntdll" ) ) == NULL )
    return( FALSE );
  pNtCreateFile = (P_NT_CREATE_FILE) GetProcAddress( hNtDLL, 
            "NtCreateFile" );
  if( pNtCreateFile == NULL )
    return( FALSE );
  UnicodeStr.Buffer = TCPDriverName;
  UnicodeStr.Length = (USHORT)(wcslen(TCPDriverName) * sizeof(WCHAR));
  UnicodeStr.MaximumLength = UnicodeStr.Length + sizeof(UNICODE_NULL);
  objectAttributes.Length = sizeof( OBJECT_ATTRIBUTES );
  objectAttributes.ObjectName = &UnicodeStr;
  objectAttributes.Attributes = OBJ_CASE_INSENSITIVE;
  objectAttributes.RootDirectory = NULL;
  objectAttributes.SecurityDescriptor = NULL;
  objectAttributes.SecurityQualityOfService = NULL;
  rVal = pNtCreateFile( pTCPDriverHandle,
                       SYNCHRONIZE | GENERIC_EXECUTE,
                       &objectAttributes,
                       &ioStatusBlock,
                       NULL,
                       FILE_ATTRIBUTE_NORMAL,
                       FILE_SHARE_READ | FILE_SHARE_WRITE,
                       FILE_OPEN_IF,
                       FILE_SYNCHRONOUS_IO_NONALERT,
                       NULL,
                       0 );
  if( rVal < 0 )
  {
    printf( "\nFailed to create TCP Driver handle; NT status code = %d.", rVal );
    *pTCPDriverHandle = INVALID_HANDLE_VALUE;
    return( FALSE );
  }
  return( TRUE );
}
/*  Function:              GetEntityList
    Description:
      Allocates a buffer for and retrieves an array of TDIEntityID 
    structures that identifies the entities supported by 
    the TCP/IP device driver.
    Parameters:
      TCPDriverHandle  --  An open handle to the TCP Driver; if 
            no such handle is available, 
            may be INVALID_HANDLE_VALUE.
      lplpEntities     --  Pointer to a buffer that contains 
            the array of TDIEntityID structures. 
            Must be freed by the calling process 
            using LocalFree( ).
    Return Value:
      DWORD  --  the number of entity structures in the returned array
*/
DWORD GetEntityArray( IN HANDLE TCPDriverHandle, 
    OUT TDIEntityID **lplpEntities )
{
  TCP_REQUEST_QUERY_INFORMATION_EX  req;
  DWORD arrayLen = sizeof(TDIEntityID) * MAX_TDI_ENTITIES;
  DWORD bufferLen = arrayLen;
  TDIEntityID * pEntity = NULL;
  NTSTATUS status = TDI_SUCCESS;
  DWORD temporaryHandle = 0;
  int i;
// First, if the handle passed in is not valid, try to obtain one.
  if( TCPDriverHandle == INVALID_HANDLE_VALUE )
  {
    if( GetTCPHandle( &TCPDriverHandle ) == FALSE )
    {
      *lplpEntities = NULL;
      return( 0 );
    }
    temporaryHandle = TRUE;
  }
// Next, set up the input structure for the IOCTL operation.
  req.ID.toi_entity.tei_entity    = GENERIC_ENTITY;
  req.ID.toi_entity.tei_instance  = 0;
  req.ID.toi_class                = INFO_CLASS_GENERIC;
  req.ID.toi_type                 = INFO_TYPE_PROVIDER;
  req.ID.toi_id                   = ENTITY_LIST_ID;
// The loop below is defensively engineered:
// (1)  In the first place, it is unlikely that more 
//     than MAX_TDI_ENTITIES of TCP/IP entities exist, 
//     so the loop should execute only once.
// (2)  Execution is limited to 4 iterations to rule out 
//     infinite looping in case of parameter corruption. Only 2
//     iterations should ever be necessary unless entities are 
//     being added while the loop is running.
  for( i = 0; i < 4; ++i )
  {
    if( pEntity != NULL )
    {
      LocalFree( pEntity );
      pEntity = NULL;
      bufferLen = arrayLen;
    }
    if( arrayLen == 0 )
      break;
    pEntity = (TDIEntityID *) LocalAlloc( LMEM_FIXED, bufferLen );
    if( pEntity == NULL )
    {
      arrayLen = 0;
      break;
    }
    if( !DeviceIoControl( TCPDriverHandle, // Handle to TCP driver
                          IOCTL_TCP_QUERY_INFORMATION_EX, // Cmd code
                          &req,            // Pointer to input buffer
                          sizeof(req),     // Size of ipt buffer
                          pEntity,         // Ptr to output buffer
                          bufferLen,       // Size of output buffer
                          &arrayLen,       // Actual size of array
                          NULL ) )
      status = GetLastError( );
    // Even if the output buffer is too small, the TCP driver 
    // returns a status of TDI_SUCCESS; it is the value returned in
    // arrayLen that indicates whether the entire array was 
    // successfully copied to the output buffer.
    if( status == TDI_SUCCESS )
    {
      if( arrayLen && ( arrayLen <= bufferLen ) )
        break;
    }
    else
      arrayLen = 0;
  }
  if( temporaryHandle )
    CloseHandle( TCPDriverHandle );
  *lplpEntities = pEntity;
  return( (DWORD)( arrayLen / sizeof(TDIEntityID) ) );
}
int main( )
{
  DWORD i;
  DWORD entityCount;
  TDIEntityID
    *entityArray,
    *entityPtr;
  if( !( entityCount = GetEntityArray( INVALID_HANDLE_VALUE, 
    &entityArray ) ) )
    return( 1 );
  entityPtr = entityArray;
  printf( "\n\nList of %d Transport Driver Interface Entities on this machine:\n", entityCount );
  for( i = 0; i < entityCount; ++i )
  {
    printf( "\n  Entity #%d:\n    Category (tei_entity) is ", i );
    switch( entityPtr->tei_entity )
    {
      case GENERIC_ENTITY:
        printf( "Generic." );
        break;
      case CL_NL_ENTITY:
        printf( "Connectionless Network-Layer (CL_NL)" );
        break;
      case CO_NL_ENTITY:
        printf( "Connected Network-Layer (CO_NL)" );
        break;
      case CL_TL_ENTITY:
        printf( "Connectionless Transport-Layer (CL_TL)" );
        break;
      case CO_TL_ENTITY:
        printf( "Connected Transport-Layer (CO_TL)" );
        break;
      case AT_ENTITY:
        printf( "Address Translation (AT)" );
        break;
      case IF_ENTITY:
        printf( "Interface (IF)" );
        break;
      case ER_ENTITY:
        printf( "Echo Request/Response (ER)" );
        break;
      default:
        printf( "[Unidentified Entity Type] = 0x%x", 
        entityPtr->tei_entity );
    }
    printf( "\n Instance (tei_instance) = %d\n", 
        entityPtr->tei_instance );
    ++entityPtr;
  }
//  Free the entity-array buffer before quitting.
    LocalFree( entityArray );
  return( 0 );
}
要求
| 要求 | 价值 | 
|---|---|
| 标头 | tcpioctl.h |