Search code examples
c++cwindowspowershellwinapi

powershell's "get-netadapter" replacement using C/C++ APIs


I need to obtain the network adapter GUID given the connection name as shown by Windows network manager. Powershell's get-netadapter does the job, but I'd like to do it in C/C++. I know that thare are two set of API function/methods:

  • iphlpapi.h
  • netlistmgr.h

Both seems to do part of the work. In particular, by IEnumNetworks and related classes I managed to list some networks/adapters. E.G., this is the output of get-netadapter:

Name                      InterfaceDescription                    ifIndex Status       MacAddress             LinkSpeed
----                      --------------------                    ------- ------       ----------             ---------
My Tunnel                 TAP-Windows Adapter V9 #2                    40 Disconnected 00-FF-E6-0A-89-C6         1 Gbps
Ethernet 4                Intel(R) PRO/1000 MT Desktop Adapter #2      30 Up           08-00-27-95-74-A2         1 Gbps
Local Area Connection     TAP-Windows Adapter V9                       15 Disconnected 00-FF-CC-95-DA-46         1 Gbps
Ethernet 3                Intel(R) PRO/1000 MT Desktop Adapter          4 Up           08-00-27-AC-C1-5A         1 Gbps

My goal is to get "My Tunnel" adapter object (ifIndex or GUID, at least), but when the network is not "connected", I don't get any adapter. Here my "quick and dirty" test program (error checks, main and includes omitted for clarity):

CoInitializeEx(NULL, COINITBASE_MULTITHREADED);

// get a network list manager object
INetworkListManager *mgr;
CoCreateInstance(CLSID_NetworkListManager, NULL, CLSCTX_ALL, IID_INetworkListManager, (LPVOID*)&mgr);

// get the enumerator for existing networks    
IEnumNetworks *enn;
mgr->GetNetworks(NLM_ENUM_NETWORK_ALL, &enn);
for (;;) {
    INetwork *net;
    ULONG n = 0;
    if (S_OK != enn->Next(1, &net, &n) || n < 1)
        break; 

    // print the name of current network object
    BSTR str;
    net->GetName(&str); printf(" Name: %ws\n", str); SysFreeString(str);
  
    // get the enumerator for network connections belonging to the current network                          
    IEnumNetworkConnections *enc;
    net->GetNetworkConnections(&enc);
    INetworkConnection *nc;
    for (;;) {
        if (S_OK != enc->Next(1, &nc, &n))
            break;
        // explore the list of connections and print the adapter's GUID
        nc->GetAdapterId(&g);
        printf(" Adapter: {%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\n",
               g.Data1, g.Data2, g.Data3, g.Data4[0], g.Data4[1], g.Data4[2],
               g.Data4[3], g.Data4[4], g.Data4[5], g.Data4[6], g.Data4[7]);
    }
}

Here the output I get:

 Name: Network
 Name: Local Area Connection
 Name: mygroup.net
 Adapter: {e1b4e605-c6ee-4f03-b4c6-0d879a27669b}
 Name: My Tunnel
 Name: Unidentified network
 Adapter: {12d9ae29-7863-414f-b195-e1230d8c697b}

"My Tunnel" doesn't seem to have any adapter, although powershell is able to retrieve it. The adapter appears only after I established a connection (a VPN in this case). How can I get the adapters in the same way powershell does?

NOTE: what I need is the ability to get the network adapter given the network name. By iphlpapi I can retreive other information (e.g. InterfaceDescription), but not the network name. It seems that the "network name" is not part of the "core networking" of Windows, but of a sort of managing layer instead. So, the only solution I have found right now is CreateProcess("powershell.exe",...)... uhm...


Solution

  • Thanks to Jeaninez-MSFT, it turned out that the function GetAdaptersAddresses, in spite of its name, returns much more information. In particular, field "FriendlyName" contains the string that powershell's get-netadapter shows in the "Name" column. MS documentation contains a working demo program.