
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".
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.
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:
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:
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!
| You must Sign In to use this message board. |
|
|
 |
|
 |
Hi,
How can i change the IP address of a particular adapter ... I found some way by changing the setting under registry editor but can't do it dynamically it requires a pc reboot to set the new IP address.
Please help....!!! 
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Hmmm, I really don't know but I will try running the program again and see if I can find something. Last time I tried to run it I ran into problems, but I will try again. In the meantime try googling for an answer
Rafique Sheikh
"The truth will set you free but first it will piss you off".
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
I have used the same method to get the mac of adapters, but I can not distinct all type of network card.
Such as wire adapter, wireless adapter, also now there is bluetooth adapter and mobile boardband adapter...
you said the first adapter in the "ipconfig/all" is the primary, but the index will change when you
restart your computer. Oh,my god! I has been in trouble to get the primary network card!
Could give me some advice?
Thank you!
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
From my testing I found that the first adapter in the array of adapters was always the primary adapter. I hope this helps.
Rafique Sheikh
"The truth will set you free but first it will piss you off".
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Hi all,
http://www.codeproject.com/KB/IP/NetCnfgVersion2.aspx
The above link for configuring network settings was really helpful but i want to know more info about a local NIC card.
1.)How can i find the Connection Speed(Link Speed) of the NIC(e.g 100mbps or 1Gbps) programmatically ? As we can see this in windows "Local Area Connection Status" dialog.
(You are not displaying the connection speed in your application.)
2.)Also how can i change this connection(Link) speed programmatically(VC++)..???
Please Help,
Thanks,
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
While trying to compile it on VS2008 I got these errors:
netadapter.cpp:
Line 126: error C2065: 'IP_PER_ADAPTER_INFO' : undeclared identifier Line 126: error C2065: 'pPerAdapt' : undeclared identifier Line 191: error C2039: 'GetPerAdapterInfo' : is not a member of '`global namespace'' Line 191: error C2065: 'pPerAdapt' : undeclared identifier Line 191: error C3861: 'GetPerAdapterInfo': identifier not found Line 193: error C2065: 'pPerAdapt' : undeclared identifier Line 193: error C2065: 'IP_PER_ADAPTER_INFO' : undeclared identifier Line 193: error C2059: syntax error : ')' Line 194: error C2039: 'GetPerAdapterInfo' : is not a member of '`global namespace'' Line 194: error C2065: 'pPerAdapt' : undeclared identifier Line 194: error C3861: 'GetPerAdapterInfo': identifier not found Line 200: error C2065: 'pPerAdapt' : undeclared identifier Line 200: error C2227: left of '->DnsServerList' must point to class/struct/union/generic type Line 210: error C2065: 'pPerAdapt' : undeclared identifier Line 210: error C2065: 'pPerAdapt' : undeclared identifier
My system is this:
Windows Vista VS2008 Team Windows SDK 6.0a
Any Suggestions?
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Its been a long time since I worked on this project. I will try to compile it under VS2008 and see if I can figure out where the errors are coming from
Thanks
Rafique Sheikh
"The truth will set you free but first it will piss you off".
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
had the same problem, which resolves to
#if (NTDDI_VERSION >= NTDDI_WIN2KSP1) in the iptypes.h
which leeds to an update in the stdafx.h
#define _WIN32_WINNT 0x0501
thanx for the article
Press F1 for help or google it. Greetings from Germany
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
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".
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Could you tell me how to get Primary (not other) physical MAC address in Visual Basic 6.0? I actually need this code.
Thanks!
|
| Sign In·View Thread·PermaLink | 2.00/5 |
|
|
|
 |
|
 |
I am not very well versed in VB6 but I suppose you could easily port thecode over, it shouldn't be too difficult.
Rafique Sheikh
"The truth will set you free but first it will piss you off".
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Is it possible to determine if a MAC address is a physical device or a software device...
Such as a VPN connection or a mimic device such as VirtNet?
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
This is a good question. I am not sure we can tell whether a given MAC is physical or virtual but I will dig into it.
Rafique Sheikh
"The truth will set you free but first it will piss you off".
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
 |
Well, like I said I asumed that the adapter with the lowest index in the array m_pAdapters was the primary adapter. I did not find a definitive answer to how to determine the primary index on a multihomed machine. In your cae it appears that your VMWare adapter is the adapter with the lowest index. It may not make sense but that how windows returns the adapters. I hope this helps.
Rafique Sheikh
"The truth will set you free but first it will piss you off".
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
 |
No,
Unfortunately I did not find any more definitive answer to that. My initial assumptions are what I am standing by.
Rafique Sheikh
"The truth will set you free but first it will piss you off".
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
 |
Use the code in thi sarticle as a base and try to find similar functions in .Net I am sure you will be able to get it done in .Net compact framework.
Rafique Sheikh
"The truth will set you free but first it will piss you off".
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Hello ghulam-e-sirsabz,
I found two "strange" things.
1) ip and subnetmask are not filled when the networkdevice is disconnected from hub/switch. See appendix A for the details.
2) I haven't see information in m_sCurIpAddr. pAdaptInfo->CurrentIpAddress seems to NULL at my pc. I know that the ip/subnet has to be retrieved in the (AdaptInfo->IpAddressList) list. But, on what circumstance will m_sCurIpAddr be filled? See Appendix B also.
Greetings Jan Marco
Appendix A: INSERT INTO networkdetail (date,time,id,iddevice,type,ip,subnetmask) VALUES ('20060423','09:56:13',0,1,'ip','192.168.0.141','255.255.255.0'); INSERT INTO networkdetail (date,time,id,iddevice,type,ip,subnetmask) VALUES ('20060423','09:56:13',1,1,'gateway','192.168.0.1','0.0.0.0'); UPDATE network SET PrimaryAdapter='Yes' WHERE id=0;
Now it disconnect the ethernet card from switch:
INSERT INTO networkdetail (date,time,id,iddevice,type,ip,subnetmask) VALUES ('20060423','09:59:12',0,1,'ip','0.0.0.0','0.0.0.0'); INSERT INTO networkdetail (date,time,id,iddevice,type,ip,subnetmask) VALUES ('20060423','09:59:12',1,1,'gateway','','');
Appendix B:
if( pAdaptInfo->CurrentIpAddress ) { m_sCurIpAddr.sIp = pAdaptInfo->CurrentIpAddress->IpAddress.String; m_sCurIpAddr.sSubnet = pAdaptInfo->CurrentIpAddress->IpMask.String;
}
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
The program should end if it does not find any network adapters on the system or if the adapters are all disconnected. It doesn't even make it as far as the SetupAdapterInfo(...) function which you are referring to above in Appendix B. So yes the ip and subnet mask will not be filled when "the network device is disconnected from hub/switch". Look in function EnumNetworkAdapters(...) and BuildAdapterListing() for a better understanding. The ip and subnet mask will only be filled when you are working with a valid and connected network adapter.
ghulam-e-sirsabz
|
| Sign In·View Thread·PermaLink | 1.00/5 |
|
|
|
 |
|
 |
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.
How to change the binding order of network adapters
probably this helps you a little bit
either you live or you are consequent
|
| Sign In·View Thread·PermaLink | 2.00/5 |
|
|
|
 |
|
 |
Thanks for the link. This link describes how to change the binding order but doesn't explain how to determine which is the primary adapter on a multi-homed system. If I use "ipconfig /all" at the command prompt I get a listing of my network adapters in a different order than the one shown in the "Control Panel->Network Conections->Advanced->Advanced Settings" tab (mentioned in the article). I think the adapter listed first in response to the "ipconfig /all" command is the primary adapter.
ghulam-e-sirsabz
|
| Sign In·View Thread·PermaLink | 2.86/5 |
|
|
|
 |
|
|