Windows10 c++ obtains network card information (ipv4, subnet mask, gateway, mac address)

About

The style environment of this article: win10 + vs2017 + c++11

1.Description

It’s a trap. I always thought that a network card can only have one IP. Today I found that in the structure, the relevant structure is defined: One network card can use Multiple IPs.

2. Connection library and header file

  • 2.1 Header files
#include <WinSock2.h>
#include <Iphlpapi.h>
  • 2.2 Library
Iphlpapi.lib

3. Encapsulation class

I made a package myself and just use it later.

  • 3.1 Header file source code
#pragma once
#include <string>
#include <list>


#if defined(_WIN32) || defined(_WIN64)
#ifndef os_is_win
#define os_is_win
#endif // !os_is_win

#elif defined(__linux__) || defined(_linux_) || defined(__unix) || defined(_unix_) || defined(_APPLE_)
#ifndef os_is_linux
#define os_is_linux
#endif // !os_is_linux
\t
#endif// ! defined(_WIN32) || defined(_WIN64)




#if defined(os_is_win)

#ifndef _net_api_export_
#define _net_api_export_ __declspec(dllexport)
#else
#define _net_api_export_ __declspec(dllimport)
#endif // !#ifndef _net_api_export_

#elif defined(os_is_linux)

#ifndef _net_api_export_
#define _net_api_export_ __attribute__((visibility ("default")))
#endif // !_net_api_export_

#endif //! defined(os_is_win)



namespace lib_net
{


/**
* @brief: ip information
*/
struct ip_info_
{
std::string _inet4;
std::string _inet6;
std::string _subnet_mask;
std::string _gate;

void zero()
{
_inet4 = { "" };
_inet6 = { "" };
_subnet_mask = { "" };
_gate = { "" };
}


ip_info_()
{
zero();
}
};

using ip_info = ip_info_;
using ip_list = std::list<ip_info>;


/**
* @brief: the information of adapter
*/
struct net_adapter_info_
{
#ifdef os_is_win
int _index;
#endif //! os_is_win

std::string _name;
std::string _description;
std::string _dev_type;
std::string _mac;

ip_list_ip;
int _ip_size;

void zero()
{
#ifdef os_is_win
_index = 0;
#endif //! os_is_win
_name = { "" };
_description = { "" };
_dev_type = { "" };
_mac = { "" };
_ip.clear();
_ip_size = 0;
}

net_adapter_info_()
{
zero();
}
};

// to rename the type
using net_ada_info = net_adapter_info_;

// maybe, this machine has greater than 1 adapter
using net_ada_list = std::list<net_ada_info>;

//------------------------------------------------ ----------------------------------------




/**
* @brief: you could get the adapter information through this class on windows, linux and osx
*/
class _net_api_export_ net_adapter_helper
{
public:
//------------------------------------------------ ----------------------------------------
\t\t
static net_adapter_helper & amp; get_instance();

/**
* @brief: Get Windows network card information
*/
net_ada_list get_info_win();




private:
template<typename ... Args>
static std::string str_format(const std::string & amp;format, Args ... args)
{
auto size_buf = std::snprintf(nullptr, 0, format.c_str(), args ...) + 1;
std::unique_ptr<char[]> buf(new(std::nothrow) char[size_buf]);

if (!buf)
return std::string("");

std::snprintf(buf.get(), size_buf, format.c_str(), args...);

return std::string(buf.get(), buf.get() + size_buf - 1);
}

//------------------------------------------------ ----------------------------------------
net_adapter_helper() = default;
virtual ~net_adapter_helper() = default;

net_adapter_helper(const net_adapter_helper & amp; instance) = delete;
net_adapter_helper & amp; operator = (const net_adapter_helper & amp; instance) = delete;
net_adapter_helper(const net_adapter_helper & amp; & amp; instance) = delete;
net_adapter_helper & amp; operator = (const net_adapter_helper & amp; & amp; instance) = delete;

};
}
  • 3.2 Source file source code
#include "ip_helper.h"

#include 
#include 

#if defined(os_is_win)
#include <WinSock2.h>
#include <Iphlpapi.h>
#endif //! defined(os_is_win)



namespace lib_net
{

/**
* @brief:
*/
lib_net::net_adapter_helper & net_adapter_helper::get_instance()
{
static net_adapter_helper instance;

return instance;
}


/**
* @brief:
*/
lib_net::net_ada_list net_adapter_helper::get_info_win()
{
net_ada_list ret_list;

std::unique_ptr< IP_ADAPTER_INFO> pai(new(std::nothrow) IP_ADAPTER_INFO);

// 1. failed to apply space
if (nullptr == pai || NULL == pai)
return ret_list;

// 2. to get the size of IP_ADAPTER_INFO structure
unsigned long iai_size = sizeof(IP_ADAPTER_INFO);

// 3. Call the GetAdaptersInfo function and fill in the pIpAdapterInfo pointer variable; where the stSize parameter is both an input quantity and an output quantity.
int ret_val = GetAdaptersInfo(pai.get(), & amp;iai_size);

if (ERROR_BUFFER_OVERFLOW == ret_val)
{
pai.release();

//Reapply for memory space to store all network card information
pai.reset((IP_ADAPTER_INFO*)(new(std::nothrow) char[iai_size]));

if (nullptr == pai || NULL == pai)
{
return ret_list;
}

//Call the GetAdaptersInfo function again to fill in the pIpAdapterInfo pointer variable
ret_val = GetAdaptersInfo(pai.get(), & amp;iai_size);
}

if (ERROR_SUCCESS == ret_val)
{
// 3. to get information
net_ada_info item;
IP_ADAPTER_INFO *ppai = pai.get();

while (ppai)
{
item._index = ppai->Index;
item._name = std::string(ppai->AdapterName);
item._description = std::string(ppai->Description);

// dev
std::string str_type;
switch (ppai->Type)
{
case MIB_IF_TYPE_OTHER:
str_type = {"OTHER"};
break;

case MIB_IF_TYPE_ETHERNET:
str_type = { "ETHERNET" };
break;

case MIB_IF_TYPE_TOKENRING:
str_type = { "TOKENRING" };
break;

case MIB_IF_TYPE_FDDI:
str_type = { "FDDI" };
break;

case MIB_IF_TYPE_PPP:
str_type = { "PPP" };
break;

case MIB_IF_TYPE_LOOPBACK:
str_type = { "LOOPBACK" };
break;

case MIB_IF_TYPE_SLIP:
str_type = { "SLP" };
break;

default:
str_type = { "" };
break;
}

item._dev_type = str_type;

//mac
std::string str_mac;
for (DWORD i = 0; i < ppai->AddressLength; i + + )
{
if (i < ppai->AddressLength - 1)
str_mac + = str_format(" X-", ppai->Address[i]);
else
str_mac + = str_format(" X", ppai->Address[i]);
}

item._mac = str_mac;



// IP information
ip_info ii_item;
IP_ADDR_STRING *pial = & amp;(ppai->IpAddressList);
int ip_size = 0;
for (;;)
{
if (NULL != pial & amp; & amp; nullptr != pial)
{
ii_item._inet4 = std::string(pial->IpAddress.String);
ii_item._subnet_mask = std::string(pial->IpMask.String);
ii_item._gate = std::string(pai->GatewayList.IpAddress.String);

item._ip.push_back(ii_item);
pial = pial->Next;
ii_item.zero();
ip_size + + ;
}
else
{
break;
}
}

item._ip_size = ip_size;
ret_list.push_back(item);
item.zero();

ppai = ppai->Next;
} // end while
}
else
{
;// error
}

return ret_list;
}

}

4.Use

net_ada_list nal = net_adapter_helper::get_instance().get_info_win();
int list_size = nal.size();

cout << "1.Number of adapters = " << list_size << "\
\
" << endl;

#if defined(os_is_win)
for (auto item : nal)
{
    cout << "index=" << item._index << endl;
    cout << "name=" << item._name.c_str() << endl;
    cout << "Description=" << item._description.c_str() << endl;
    cout << "type=" << item._dev_type.c_str() << endl;
    cout << "MAC=" << item._mac.c_str() << endl;
    
    int index = 0;
    cout << "ip has=" << item._ip_size << "pieces" << endl;
    for (auto item_ip : item._ip)
    {
        cout << "th" << + + index << "ip" << endl;
        cout << "ipv4 = " << item_ip._inet4.c_str() << endl;
        cout << "Subnet mask = " << item_ip._subnet_mask.c_str() << endl;
        cout << "Gateway = " << item_ip._gate.c_str() << endl;
        cout << "\
-------------------------";
    }

    cout << "\
-------------------------------------------------- ------\
\
";
}

#endif //