Click here to Skip to main content
15,881,898 members
Articles / Desktop Programming / MFC
Article

Getting the Physical (MAC) address of a Network Interface Card and finding out if it is the primary adapter on a multi-homed system

Rate me:
Please Sign up or sign in to vote.
4.80/5 (22 votes)
14 Mar 2006CPOL4 min read 234.9K   15.5K   107   34
This article describes how to obtain a Network Interface Card's (NIC) Physical or Ethernet (MAC) address. It also shows how to identify if a network adapter is the primary adapter on a multi-homed system. If not, it shows how to find and get the primary adapter's IP and MAC addresses.

NetCfg - Version 2 Demo

Note: The actual IP and MAC addresses have been replaced by fictitious values for safety reasons.

Introduction

This article describes how to get the MAC or physical address of a network adapter, and how to tell if an adapter is the primary adapter on the system given its adapter (system) index. Finally, it shows how to get the (array) index of the primary adapter. It is based on an article by Joseph Dempsey: The "New ipconfig" and the IP Helper API.

Background

While "ipconfig /all" can be used to obtain detailed information about the IP configuration of a system, from the Windows command prompt, sometimes, we need this information in an application. There are many ways to do this, one of which may be to send the "ipconfig /all" command from your application and then parse the results for specific information you are looking for; however, this method gives you just the information and no real control over the network adapter.

The CNetworkAdapter class does both, it not only provides you with information but also lets you perform useful network configuration tasks such as renewing or releasing a lease on the network adapter. The "NetCfg -- The Sequel" project in Joseph's original article provided all of the above functionality. I needed to get the MAC address of a network adapter as well as find out if it was the primary adapter on a multi-homed system (a system with more than one Network Interface Card). Therefore, I decided to modify the CNetworkAdapter class by adding this new functionality. I also had to modify the CNetCfgDlg class to add functions to find if an adapter with a given index was the primary adapter, and to find out the index of the primary adapter and show its information.

Using the code

The groundwork for getting the MAC address of a network adapter was already laid out in Joseph's article. I had to modify the BOOL CNetworkAdapter::SetupAdapterInfo(IP_ADAPTER_INFO* pAdaptInfo ) function by first setting the adapter address length, and then copying each byte from pAdaptInfo->Address (the MAC address) to the adapter address structure as shown below:

BOOL CNetworkAdapter::SetupAdapterInfo(IP_ADAPTER_INFO* pAdaptInfo )

.....
m_ucAddress.nLen = pAdaptInfo->AddressLength;
for (int i = 0; i < (int) m_ucAddress.nLen; i++)
{
    m_ucAddress.ucAddress[i] = pAdaptInfo->Address[i];
}
.....

Getting the MAC Address

I wrote two overloaded functions to get the MAC address: one returns the address formatted as a standard MAC address in HEX, punctuated with hyphens, e.g., "00-12-34-AB-CD-EF".

// rsheikh: returns formatted MAC address in HEX punctuated with hyphens "-"
tstring CNetworkAdapter::GetAdapterAddress(void)
{
    tstring sAddr = _T("");
    CString sTemp = _T("");
    for (unsigned int i = 0; i < m_ucAddress.nLen; i++)
    {
        if(i > 0)
        {
            sAddr += "-";
        }

        sTemp.Format("%02X", m_ucAddress.ucAddress[i]);
        sAddr += sTemp;
    }

    return sAddr;
}

The other copies the raw MAC address bytes into a CByteArray passed into the function.

// rsheikh: copies the adapter's address raw bytes
// into the CByteArray pointed to by pAdapterAddress
void CNetworkAdapter::GetAdapterAddress(CByteArray& pAdapterAddress)
{
    for (unsigned int i = 0; i < m_ucAddress.nLen; i++)
    {
        pAdapterAddress.Add(m_ucAddress.ucAddress[i]);
    }
}

Finding out if the adapter with the given index is the primary adapter

In order to find out if the adapter with the given index is the primary adapter, I had to add a function to the dialog class CNetCfgDlg. This code iterates over the m_pAdapters array, comparing the given adapter index with the index for each adapter in the array. If the given adapter index is equal to the smallest index of all adapters in the array, then it is the primary adapter:

// Rafique Sheikh: This function can be used
// to find out if an Adapter with the given Index
// is the primary adapter.
bool CNetCfgDlg::IsPrimaryAdapter(DWORD dwIndex)
{
    bool bIsPrimaryAdapter = false;
    if( m_pAdapters ) 
    {    
        CNetworkAdapter* pAdapt = NULL;

        DWORD dwMinIndex = m_pAdapters->GetAdapterIndex() ;
        for (unsigned int i = 0; i < m_nCount; i++)
        {
            pAdapt = &m_pAdapters[ i ];
            if(pAdapt->GetAdapterIndex() < dwMinIndex)
            {
                dwMinIndex = pAdapt->GetAdapterIndex();
            }

        }

        if (dwIndex == dwMinIndex)
            bIsPrimaryAdapter = true;
    }

    return bIsPrimaryAdapter;
}

If the currently displayed/selected adapter is the primary adapter, the application GUI indicates that with a "YES", if not the GUI shows a "NO" and also makes the information for the primary adapter visible.

Getting the index of the primary adapter

In order to get information for the primary adapter, I had to add another function to CNetCfgDlg:

// Rafique Sheikh: This function returns the actual
// zero-based index of the Primary Adapter within the
// array of Adpaters pointed to by m_pAdapters 
int CNetCfgDlg::GetPrimaryAdapterIndex(void)
{
    int nPrimaryAdapterIndex = -1;
    if( m_pAdapters ) 
    {    
        CNetworkAdapter* pAdapt = NULL;
        DWORD dwMinIndex = m_pAdapters->GetAdapterIndex() ;
        nPrimaryAdapterIndex = 0;
        for (unsigned int i = 0; i < m_nCount; i++)
        {
            pAdapt = &m_pAdapters[ i ];
            if(pAdapt->GetAdapterIndex() < dwMinIndex)
            {
                dwMinIndex = pAdapt->GetAdapterIndex();
                nPrimaryAdapterIndex = i;
            }
        }
    }

    return nPrimaryAdapterIndex;
}

Once we have the index of the primary adapter, we can find all information about it from the array m_pAdapters.

Points of Interest

Getting the MAC address of a network adapter using the CNetworkAdapter class was simple. Finding which adapter is the primary on a computer system required some research on the topic. I could not find an authoritative answer to this question. It made sense that the first adapter listed in the response to the ipconfig /all command would be the primary, but I had no way to confirm this. The closest thing I found as an answer was an article by CISCO.

So it appeared that my assumption above was correct. I consistently found that the first adapter listed in response to ipconfig /all had the lowest index in the array m_pAdapters. The functions listed above to find out if the adapter with the given index was the primary and to find the index of the primary adapter are based on this assumption.

For instance, on a system with two network adapters, NIC1 and NIC2, let's say the adapter index for NIC1 is 65540 whereas the index for NIC2 is 65539, thus, based on the assumption I just listed, NIC2 is the primary adapter. When I talk about the index of the primary adapter, I do not mean the adapter's index on the computer system (65539 or 65540, in this case) but rather in the array m_pAdapters (0 or 1 in this case, since we only have two adapters). In this example, the index for NIC2 is 1 even though it is the primary adapter. It sounds strange but that is how the adapters get added to the array m_pAdapters, and that is why we need the functions listed above to find all this information.

If someone has a definite answer to "how to find the primary adapter on a multi-homed system?", I would love to hear about it.

That's it! Please go ahead and experiment, suggest other ways to accomplish the same. Enjoy!

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer
United States United States
Although an electrical engineer by major, I slowly transformed into a software developer as I realized I liked working with logical AND and ORs more than the physical ones on chips. I have taught C++ at ITT tech and worked on videoconferencing as a programmer. A summer class at Harvard got me into windows programming and I have enjoyed it ever since.

I like hiking, camping, walking and swimming. Tennis gets me going too as does discussing human psychology.

Comments and Discussions

 
Questiontest network adapter offlie Pin
rezanazari25-Dec-17 15:47
rezanazari25-Dec-17 15:47 
QuestionNetwork adapter physical LAN card MAC address Pin
Member 106070048-Dec-15 6:21
Member 106070048-Dec-15 6:21 
QuestionTwo issues not answered yet from the original but still applying this article's source code too Pin
ehaerim1-Mar-12 7:46
ehaerim1-Mar-12 7:46 
AnswerRe: Two issues not answered yet from the original but still applying this article's source code too Pin
Rafique Sheikh15-Mar-12 10:32
Rafique Sheikh15-Mar-12 10:32 
QuestionProgram crashed when displaying details of Primary Adapter Pin
quanghao11-Oct-11 20:43
professionalquanghao11-Oct-11 20:43 
AnswerRe: Program crashed when displaying details of Primary Adapter Pin
Rafique Sheikh15-Mar-12 10:20
Rafique Sheikh15-Mar-12 10:20 
Generalit's really useful Pin
Nice Gom12-Jul-11 18:33
Nice Gom12-Jul-11 18:33 
GeneralRe: it's really useful Pin
Rafique Sheikh13-Jul-11 9:16
Rafique Sheikh13-Jul-11 9:16 
QuestionHow to change the IP address of the adapter without restarting the PC..??? Pin
Rookie_Coder22-Sep-09 1:44
Rookie_Coder22-Sep-09 1:44 
AnswerRe: How to change the IP address of the adapter without restarting the PC..??? Pin
Rafique Sheikh22-Sep-09 3:52
Rafique Sheikh22-Sep-09 3:52 
GeneralAbout primary adapter Pin
zwhate31-Aug-09 1:58
zwhate31-Aug-09 1:58 
GeneralRe: About primary adapter Pin
Rafique Sheikh4-Sep-09 15:22
Rafique Sheikh4-Sep-09 15:22 
GeneralRe: About primary adapter Pin
Shawn.Liao26-Dec-12 0:02
Shawn.Liao26-Dec-12 0:02 
QuestionLocal Area Connection (Link) speed Status...??? Pin
Rookie_Coder16-Jun-09 0:40
Rookie_Coder16-Jun-09 0:40 
QuestionCompile Errors VS2008 Pin
notaclue124-Mar-09 9:03
notaclue124-Mar-09 9:03 
AnswerRe: Compile Errors VS2008 Pin
Rafique Sheikh6-Mar-09 7:26
Rafique Sheikh6-Mar-09 7:26 
GeneralRe: Compile Errors VS2008 Pin
KarstenK14-Jul-09 22:02
mveKarstenK14-Jul-09 22:02 
GeneralRe: Compile Errors VS2008 Pin
Rafique Sheikh15-Jul-09 18:23
Rafique Sheikh15-Jul-09 18:23 
You are welcome, are you saying you were able to resolve the compile issues by modifying the stdafx.h with the line:

#define _WIN32_WINNT 0x0501

??

Rafique Sheikh

"The truth will set you free but first it will piss you off".

GeneralRe: Compile Errors VS2008 Pin
patomalo25-Feb-10 4:19
patomalo25-Feb-10 4:19 
AnswerRe: Compile Errors VS2008 Pin
Rafique Sheikh25-Feb-10 6:52
Rafique Sheikh25-Feb-10 6:52 
QuestionCould you translate this code to VB6 Pin
Member 326778429-Aug-08 19:38
Member 326778429-Aug-08 19:38 
AnswerRe: Could you translate this code to VB6 Pin
Rafique Sheikh22-Sep-08 19:51
Rafique Sheikh22-Sep-08 19:51 
QuestionPhysical vs Virtual? Pin
Scott Aron Bloom10-May-08 9:04
Scott Aron Bloom10-May-08 9:04 
AnswerRe: Physical vs Virtual? Pin
Rafique Sheikh10-May-08 12:33
Rafique Sheikh10-May-08 12:33 
QuestionVMWare primary??? Pin
Member 246841911-Apr-08 8:02
Member 246841911-Apr-08 8:02 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.