Network Adapters and Configuration

To find out some basic information about the device's overall network configuration, such as its host name or the DNS servers that are currently being used, you can use the GetNetworkParams() function:

DWORD GetNetworkParams(FIXED_INFO *pFixedInfo, ULONG *pOutBufLen);

The first parameter, pFixedInfo, is a pointer to a FIXED_INFO structure that will receive the current configuration information; it is followed by pOutBufLen, a pointer to a ULONG that specifies the size of the pFixedInfo structure. If the function succeeds, it will return a value of ERROR_SUCCESS. If the function returns with a value of ERROR_BUFFER_OVERFLOW, the size of the variable you passed in for pFixedInfo was not large enough, and the pOutBufLen pointer will contain the actual size that you need, as shown in the following example:

FIXED_INFO *pFixedInfo = NULL;
DWORD dwSize = 0;

// Call into GetNetworkParams to get the size we need for
if(GetNetworkParams(NULL, &dwSize) != ERROR_BUFFER_OVERFLOW)
   return FALSE;

// Allocate a buffer
pFixedInfo = (FIXED_INFO *)LocalAlloc(LPTR, dwSize);
   return FALSE;

// Get the network information
if(GetNetworkParams(pFixedInfo, &dwSize) != NO_ERROR) {
   return FALSE;

// Do something with pFixedInfo here

// Remember to free the buffer when done with it

The FIXED_INFO structure used with GetNetworkParams() is defined as follows:

typedef struct {
   char HostName[MAX_HOSTNAME_LEN+4];
   char DomainName[MAX_DOMAIN_NAME_LEN+4];
   PIP_ADDR_STRING CurrentDnsServer;
   IP_ADDR_STRING DnsServerList;
   UINT NodeType;
   char ScopeId[MAX_SCOPE_ID_LEN+4];
   UINT EnableRouting;
   UINT EnableProxy;
   UINT EnableDns;

The first field, HostName, is the name of your device as defined by DNS, and is followed by the current DNS domain in the DomainName field. The next two fields, CurrentDnsServer and DnsServerList, contain information about the DNS servers that the device is currently using. CurrentDnsServer points to the primary domain server, and DnsServerList is an IP_ADDR_STRING list of servers. The IP_ADDR_STRING structure is used frequently in the IPHelper APIs for enumerating lists of IP addresses. It is defined as follows:

typedef struct _IP_ADDR_STRING {
   struct _IP_ADDR_STRING* Next;
   DWORD Context;

Because the IP_ADDR_STRING structure is used as a linked list, the Next field points to the next IP_ADDR_STRING in the list. If there are no further addresses to be enumerated, this will be a NULL value. It is followed by IpAddress, a character string (not Unicode) containing the dotted decimal representation of an IP Address (e.g., This is followed by its corresponding subnet mask in the IpMask field. These values can be converted from dotted notation to IPAddr format using the inet_addr() and inet_ntoa() functions described in Chapter 1. Finally, the Context field specifies a network table entry (NTE), which is used when adding and deleting IP addresses.

If we continue to look at FIXED_INFO, the next fields?NodeType and ScopeId?specify whether we're using a DHCP connection, and are followed by our current scope name if DHCP is enabled. The final three fields, EnableRouting, EnableProxy, and EnableDns indicate whether routing, ARP proxy services, and DNS are enabled on the local device, respectively.

Adapter Management

Now that we've taken a look at retrieving the overall device network settings, let's look at how you can get more detailed information regarding the individual network adapters. This can be accomplish by using the GetAdaptersInfo() function, which will return a linked list of IP_ADAPTER_INFO structures?each of which contains information unique to the network adapter, such as its MAC address or DHCP lease information. The GetAdaptersInfo() function is defined as follows:

DWORD GetAdaptersInfo(IP_ADAPTER_INFO *pAdapterInfo,
   ULONG *pOutBufLen);

The pAdapterInfo parameter is a pointer to a buffer that will receive the linked list of IP_ADAPTER_INFO structures when the function returns. The pOutBufLen parameter is also a pointer and should point to a ULONG buffer that contains the size of the buffer passed into the pAdapterInfo structure. Similar to the GetNetworkParams() function, if the buffer is not large enough to hold the adapter data, the function will return with an ERROR_BUFFER_OVERFLOW return value and pOutBufLen will contain the required buffer size to contain the data.

Here's what the IP_ADAPTER_INFO looks like:

typedef struct _IP_ADAPTER_INFO {
   struct _IP_ADAPTER_INFO* Next;
   DWORD ComboIndex;
   char AdapterName[MAX_ADAPTER_NAME_LENGTH+4];
   UINT AddressLength;
   DWORD Index;
   UINT Type;
   UINT DhcpEnabled;
   PIP_ADDR_STRING CurrentIpAddress;
   IP_ADDR_STRING IpAddressList;
   IP_ADDR_STRING GatewayList;
   IP_ADDR_STRING DhcpServer;
   BOOL HaveWins;
   IP_ADDR_STRING PrimaryWinsServer;
   IP_ADDR_STRING SecondaryWinsServer;
   time_t LeaseObtained;
   time_t LeaseExpires;

Table 3.1 describes the fields of the IP_ADAPTER_INFO structure.

Table 3.1. IP_ADAPTER_INFO Field Descriptions




Pointer to the next IP_ADAPTER_INFO structure. NULL if there are no further adapters




The name of the adapter


The description of the adapter


The length of the Address field


The hardware MAC address of the adapter


The adapter index


The adapter type


Specifies if DHCP is enabled on the device


Pointer to the current IP address


A linked list of IP_ADDR_STRING structures specifying the IP addresses associated with the adapter


An IP_ADDR_STRING structure specifying the default gateway associated with the adapter


An IP_ADDR_STRING structure specifying the default DHCP server associated with the adapter


Specifies if WINS is enabled


An IP_ADDR_STRING structure specifying the primary WINS server associated with the adapter


An IP_ADDR_STRING structure specifying the secondary WINS server associated with the adapter


The date/time information specifying when the current DHCP lease was obtained


The date/time information specifying when the current DHCP lease will expire

If you need more specific information about an individual adapter's configuration, such as the DNS address list, you can use the GetPerAdapterInfo() function. To use it, however, you must already know the Index of the particular adapter you want to query. This can be obtained either from the IP_ADAPTER_INFO structure's Index field or by using the GetAdapterIndex() function:

DWORD GetAdapterIndex(LPWSTR AdapterName, ULONG *pIfIndex);

The AdapterName parameter is a buffer containing the name of the adapter, followed by pIfIndex, which is a pointer to a ULONG variable that will receive the adapter index if the function returns successfully.

Once you have the obtained the adapter index, you can use the following function:

   ULONG *pOutBufLen);

The first parameter, IfIndex, is the index of the adapter, and is followed by a pointer to an IP_PER_ADAPTER_INFO structure that will receive the adapter information. The final parameter, pOutBufLen, is a pointer to the size of the buffer specified by the pPerAdapterInfo parameter.

The IP_PER_ADAPTER_INFO structure is defined as follows:

typedef struct _IP_PER_ADAPTER_INFO {
   UINT AutoconfigEnabled;
   UINT AutoconfigActive;
   PIP_ADDR_STRING CurrentDnsServer;
   IP_ADDR_STRING DnsServerList;

The first two fields of IP_PER_ADAPTER_INFO deal with the autoconfiguration status of an adapter. If it is enabled, the AutoconfigEnabled field will be set to 1; and if it is currently active, the AutoconfigActive field will also be set to 1. The last two parameters contain information about the adapter's DNS servers. The CurrentDnsServer field points to the IP address of the primary DNS server for the device, and is followed by the DnsServerList field, a linked list of IP_ADDR_STRING structures containing additional DNS servers.

The following example shows how you could get the DHCP lease information for a network adapter:

void GetDHCPExpireTime() {
   // Get the adapter information
   IP_ADAPTER_INFO *pIpAdapterInfo = NULL;
   DWORD dwAdapterSize = 0;
   TCHAR tchDHCPTime[128] = TEXT("\0");
   TCHAR tchDate[64] = TEXT("\0");
   TCHAR tchTime[64] = TEXT("\0");
   TCHAR tchOutputString[256] = TEXT("\0");
   SYSTEMTIME sysTime;

   // Find out the size of the adapter info table, allocate,
   // and call again
   if(GetAdaptersInfo(NULL, &dwAdapterSize) !=
      return FALSE;

   pIpAdapterInfo = (IP_ADAPTER_INFO *)LocalAlloc(LPTR,
      return FALSE;

   if(GetAdaptersInfo(pIpAdapterInfo, &dwAdapterSize) !=
      NO_ERROR) {
      return FALSE;

   // The DHCP lease time is in time_t format let's convert
   // it to SYSTEMTIME

   GetDateFormat(NULL, NULL, &sysTime, TEXT("ddd, MM/dd/
      yyyy "), tchDate, sizeof(tchDate));
   GetTimeFormat(NULL, NULL, &sysTime, TEXT("hh:mm:ss tt"),
      tchTime, sizeof(tchTime));
   _tcscpy(tchDHCPTime, tchDate);
   _tcscat(tchDHCPTime, tchTime);

   // Put together our output string
   wsprintf(tchDHCPTime, TEXT("%s Lease Expires: %s"),
      pIpAdapterInfo->AdapterName, tchDHCPTime);

   // Free it when we're done

void TimeToSystemTime(time_t t, SYSTEMTIME *pSysTime)

   // This function will convert a LONG time_t value to
   // a SYSTEM_TIME structure
   FILETIME ft, ftLocal;


   // Convert to File Time
   LONGLONG ll = Int32x32To64(t, 10000000) + 116444736000000000;
   ft.dwLowDateTime = (DWORD) ll;
   ft.dwHighDateTime = (DWORD) (ll >>32);

   // Convert to Local System Time
   FileTimeToLocalFileTime(&ft, &ftLocal);
   FileTimeToSystemTime(&ftLocal, pSysTime);

The last type of information specific to a particular adapter involves unidirectional network adapters, which can only receive UDP datagram packets. The GetUniDirectionalAdapterInfo() function is defined as follows:

DWORD GetUniDirectionalAdapterInfo(
   ULONG *pdwOutBufLen);

The pIPIfInfo parameter is a pointer to a buffer that will receive an array of unidirectional adapters that are specified by an IP_UNIDIRECTIONAL_ADAPTER_ADDRESS structure. Here's what the structure looks like:

   ULONG NumAdapters;
   IPAddr Address[1];

The structure contains two fields: NumAdapters, which is the number of unidirectional adapters on the devices, followed by IPAddr, an array containing actual IP addresses of those adapters.

The final parameter of the GetUniDirectionalAdapterInfo() function is pdwOutBufLen, which is a pointer to a variable that contains the size of the buffer specified in the pIPIfInfo parameter.

Network Interfaces

The network adapter functions just described work directly with the data-link layer of the TCP/IP stack. To get detailed protocol information, you have to move up on the TCP/IP stack to talk directly with the network layer. Fortunately, the IPHelper APIs have functions that do just that.

To determine exactly how many interfaces are currently available on the device, you can call the GetNumberOfInterfaces() function:

DWORD GetNumberOfInterfaces(DWORD *pdwNumIf);

The function simply takes a single parameter, a pointer to a DWORD variable that will receive the number of interfaces. If it is successful, the function will return NO_ERROR.

Internally, each interface adapter is stored as an IP_ADAPTER_INDEX_MAP structure. Most of the functions that map to an adapter's interface use this structure, which is defined as follows:

typedef struct _IP_ADAPTER_INDEX_MAP {
   ULONG Index;

The structure contains only two fields: Index, an internal index of the network interface, and the Name of the adapter. To fully enumerate the available network interfaces and their corresponding adapters, simply call the following function:


The first parameter, pIfTable, is a pointer to an IP_INTERFACE_INFO structure. This structure will contain the array of network interfaces. The other parameter, pdwOutBufLen, is a pointer to a ULONG variable that contains the size of the pIfTable parameter, in bytes.

The IP_INTERFACE_INFO structure looks like the following:

typedef struct _IP_INTERFACE_INFO {
   LONG NumAdapters;

This structure also contains only two fields: NumAdapters, which indicates how many network interface adapters are on the device, followed by the array of IP_ADAPTER_INDEX_MAP structures for each interface.

For example, if you want to enumerate the names of all network interface adapters on your device, you can do the following:

// Interface name enumeration
DWORD dwInterfaceSize = 0;

// Find out the size of the interface table
if(GetInterfaceInfo(NULL, &dwInterfaceSize) !=
   return FALSE;

pIpInterface = (IP_INTERFACE_INFO *)LocalAlloc(LPTR,
   return FALSE;

if(GetInterfaceInfo(pIpInterface, &dwInterfaceSize) !=
   return FALSE;

// Walk through the available interfaces
TCHAR tchInterfaceBuffer[256] = TEXT("\0");
for(int nInterface = 0; nInterface < pIpInterface->
  NumAdapters; nInterface++) {
   IP_ADAPTER_INDEX_MAP *pIpAdapterMapEntry = NULL;

   pIpAdapterMapEntry =
      (IP_ADAPTER_INDEX_MAP *)&pIpInterface->
   wsprintf(tchInterfaceBuffer, TEXT("Interface Name: %s
      Interface Index: %d"),pIpAdapterMapEntry->Name,

As you walk through the loop, the tchInterfaceBuffer text buffer will receive the name and interface index for each available network interface.

Now that you know a particular interface adapter's index, you can use the GetIfEntry() function to retrieve the full statistics and configuration information about the interface. The GetIfEntry() function is defined as follows:

DWORD GetIfEntry(MIB_IFROW *pIfRow);

The only parameter you need to pass in is a pointer to a MIB_IFROW structure. Before calling the function, this structure should have its dwIndex field filled in with the index of the network interface for which you want to receive information, as shown in the following example:

MIB_IFROW mibInterface;
memset(&mibInterface, 0, sizeof(MIB_IFROW));

// To get a specific interface entry, just set the dwIndex
// field before calling the GetIfEntry function
mibInterface.dwIndex = pIpAdapterMapEntry->Index;
if(GetIfEntry(&mibInterface) != NO_ERROR)
   return FALSE;

The MIB_IFROW structure contains a great deal of interesting information about a particular network interface:

typedef struct _MIB_IFROW
   DWORD dwIndex;
   DWORD dwType;
   DWORD dwMtu;
   DWORD dwSpeed;
   DWORD dwPhysAddrLen;
   DWORD dwAdminStatus;
   DWORD dwOperStatus;
   DWORD dwLastChange;
   DWORD dwInOctets;
   DWORD dwInUcastPkts;
   DWORD dwInNUcastPkts;
   DWORD dwInDiscards;
   DWORD dwInErrors;
   DWORD dwInUnknownProtos;
   DWORD dwOutOctets;
   DWORD dwOutUcastPkts;
   DWORD dwOutNUcastPkts;
   DWORD dwOutDiscards;
   DWORD dwOutErrors;
   DWORD dwOutQLen;
   DWORD dwDescrLen;

Table 3.2 describes the individual fields of the MIB_IFROW structure:

Table 3.2. MIB_IFROW Structure Fields




Name of the interface


Index that identifies the interface


Type of interface


Maximum Transmission Unit for the interface


Speed of the interface, in bits per second


The length, in bytes, of bPhysAddr


The physical MAC address of the interface


Specifies if the interface is administratively up or not


Specifies the operational status of the interface


Specifies the last time that dwOperStatus changed


The number of octets received by this interface


The number of unicast packets received by this interface


The number of non-unicast packets received by this interface


The number of incoming packets that were discarded by this interface


The number of incoming packets that were discarded because of errors by this interface


The number of incoming packets that were discarded because of an unknown protocol error by this interface


The number of octets sent by this interface


The number of unicast packets sent by this interface


The number of non-unicast packets sent by this interface


The number of outgoing packets that were discarded by this interface


The number of outgoing packets that were discarded because of errors by this interface


The length of the output queue


The length, in bytes, of bDescr


The description of the interface

If you want to change the administrative status for a particular interface, you can call the SetIfEntry() function:

DWORD SetIfEntry(MIB_IFROW *pIfRow);

The function simply takes a pointer to a MIB_IFROW structure with two populated fields: dwIndex, to specify the adapter whose status you want to change, and the dwAdminStatus field. This can be set to either MIB_IF_ADMIN_STATUS_UP (if the interface is enabled) or MIB_IF_ADMIN_STATUS_DOWN (if it is disabled).

To retrieve all the of the current interface information for all of the adapters, instead of repeatedly calling GetIfEntry(), you can use the GetIfTable() function, which is defined as follows:

DWORD GetIfTable(MIB_IFTABLE *pIfTable, ULONG *pdwSize,
   BOOL bOrder);

The pIfTable parameter should point to a MIB_IFTABLE structure that will receive the array of MIB_IF_ROW information for the adapters. The next parameter, pdwSize, needs to point to a variable that contains the size, in bytes, of the pIfTable structure (if the buffer size is too small, the function will fail and put the proper size in pdwSize). The final parameter, bOrder, specifies whether or not the function should sort the adapters by interface index.

Because there is no obvious way to know how large the pIfTable buffer should be for all of the interfaces, you will probably be better off by first calling GetIfTable() with a NULL value for the pIfTable parameter. The function call will fail, but the pdwSize pointer will tell you how large of a buffer to allocate. You can then proceed to allocate your buffer and call GetIfTable() again with the correct size.

The MIB_IFTABLE structure that you are returned from GetIfTable() looks like the following:

typedef struct _MIB_IFTABLE {
   DWORD dwNumEntries;

The structure returned is straightforward: The dwNumEntries field indicates the number of MIB_IFROW interfaces that are located in the table array.