Click here to Skip to main content
Licence 
First Posted 6 Aug 2001
Views 218,311
Bookmarked 35 times

Get MAC Address

By | 11 May 2002 | Article
Get MAC address function

GetMacAddress

Include nb30.h and link with netapi32.lib. This article is based on Q118623.

Source

typedef struct _ASTAT_
{
	ADAPTER_STATUS adapt;
	NAME_BUFFER    NameBuff[30];
} ASTAT, * PASTAT;


CString GetMacAddress(CString sNetBiosName)
{
    ASTAT Adapter;
	
    NCB ncb;
    UCHAR uRetCode;
	
    memset(&ncb, 0, sizeof(ncb));
    ncb.ncb_command = NCBRESET;
    ncb.ncb_lana_num = 0;
	
    uRetCode = Netbios(&ncb);
	
    memset(&ncb, 0, sizeof(ncb));
    ncb.ncb_command = NCBASTAT;
    ncb.ncb_lana_num = 0;
	
    sNetBiosName.MakeUpper();
	
    FillMemory(ncb.ncb_callname, NCBNAMSZ - 1, 0x20);
	
    strcpy((char *)ncb.ncb_callname, (LPCTSTR) sNetBiosName);
	
    ncb.ncb_callname[sNetBiosName.GetLength()] = 0x20;
    ncb.ncb_callname[NCBNAMSZ] = 0x0;
	
    ncb.ncb_buffer = (unsigned char *) &Adapter;
    ncb.ncb_length = sizeof(Adapter);
	
    uRetCode = Netbios(&ncb);
    
    CString sMacAddress;
	
    if (uRetCode == 0)
    {
    	sMacAddress.Format(_T("%02x%02x%02x%02x%02x%02x"),
    	    Adapter.adapt.adapter_address[0],
            Adapter.adapt.adapter_address[1],
            Adapter.adapt.adapter_address[2],
            Adapter.adapt.adapter_address[3],
            Adapter.adapt.adapter_address[4],
            Adapter.adapt.adapter_address[5]);
    }
    return sMacAddress;
}

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

Ryszard Krakowiak

Web Developer

Poland Poland

Member



Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board. (secure sign-in)
 
Search this forum  
 FAQ
    Noise  Layout  Per page   
  Refresh
Generalthis worked for me !! Pinmemberapp_devlpr18:49 21 Mar '10  
GeneralNetBios Return ErrorCode 23 (Data error (cyclic redundancy check). ) PinmemberMember 37611480:59 29 Jul '09  
GeneralNetBios API not working for Windows Vista PinmemberAnkush12320:43 12 Feb '09  
GeneralBIOS Name PinmemberSalvaThor2319:20 29 Nov '07  
QuestionWon't work ? Pinsussexcepter2k1:20 25 Sep '05  
AnswerRe: Won't work ? Pinmemberjoe_chen117:24 14 Jun '07  
GeneralGet MAC Address PinmemberJagmal19:30 1 Feb '05  
GeneraliWhat i pass to sNetBiosName Pinmemberequebal3:34 24 Dec '04  
GeneralRe: iWhat i pass to sNetBiosName Pinmemberjoe_chen117:25 14 Jun '07  
QuestionWhat do I pass in? Pinmemberpjobson5:27 2 Aug '04  
GeneralNeed Get mac address on Foxpro 2.6 under Ms-dos Pinsussmorteza_mousavi1:01 9 Jul '04  
GeneralNeed Get MAC Address Source Code and ActiveX Control or DLL Library for VB,VFP PinsussJohn Nu19:11 23 Mar '04  
Generaldetect my NIC device is connected to the LAN Pinmembertangming052020:04 5 Feb '04  
GeneralIf not connected Pinmembergcolsani11:00 7 Oct '03  
Generalthis example juste come from... Pinmemberscoubidou944@hotmail.com5:39 21 Aug '03  
GeneralRe: this example juste come from... PinmemberRyszard Krakowiak2:28 26 Aug '03  
Questionwhy I can't pass link? PinmemberShinypro21:17 8 Dec '02  
AnswerRe: why I can't pass link? PinmemberRyszard Krakowiak21:26 12 Dec '02  
GeneralProtocol independent way of getting MAC PinmemberGoran Car9:39 30 Aug '02  
GeneralRe: Protocol independent way of getting MAC Pinmembereta10:37 10 Sep '03  
GeneralRe: Protocol independent way of getting MAC Pinmemberzero.sg20:14 5 Feb '04  
GeneralRe: Protocol independent way of getting MAC Pinmemberfunvill11:34 7 Jul '06  
GeneralMAC from multiple sources. PinmemberPeter Donahue9:51 14 May '02  

 
Ryszard,
 
An excellent idea to post this to Code Project...   I ran into this problem last year and have re-used the following code many times since.   One problem with the NetBIOS method is that not all computers have NetBIOS installed.   I have found that most machines do have SNMP installed, so that is the one that I use most often.   In any case, maybe you can incorporate some of this code into an updated article.   If you would like me to send the original .h and .cpp files send me your e-mail address and I will pass them along.
 
Header File starts here.
__________________________________________________________________________
/* MacRetriever.h
* Author: Peter Donahue
* Contact (709) 891-1129 (ask for Peter)
* peter.donahue@comdev.ca
* techinterface@yahoo.ca
*
* This class simplifies the task of retrieving the MAC address of a particular
* card under MS Windows.
*/
 
#pragma once
 
#include <winsock2.h>
#include <windows.h>
#include <snmp.h>
#include <nb30.h>
 
typedef SNMPAPI (WINAPI *t_SnmpExtensionInit)(DWORD dwUptimeReference, HANDLE *phSubagentTrapEvent, AsnObjectIdentifier *pFirstSupportedRegion);
typedef SNMPAPI (WINAPI *t_SnmpExtensionQuery)(BYTE bPduType, SnmpVarBindList *pVarBindList, AsnInteger32 *pErrorStatus, AsnInteger32 *pErrorIndex);
typedef SNMPAPI (WINAPI *t_SnmpUtilOidCpy)(AsnObjectIdentifier * pOidDst, AsnObjectIdentifier * pOidSrc);
typedef int (WINAPI *t_WSAStartup)(WORD wVersionRequested, LPWSADATA lpWSAData);
typedef int (WINAPI *t_WSACleanup)();
 
typedef UCHAR (WINAPI *t_Netbios)(PNCB pncb);
 
typedef HRESULT (WINAPI *t_UuidCreate)(UUID *puuid);
 
class CMacRetriever{
public:
     CMacRetriever(void);
     ~CMacRetriever(void);
 
     bool GetMacUsingGuid(char *address, int cardIndex);
     bool GetMacUsingNetBIOS(char *address, int cardIndex);
     bool GetMacUsingSNMP(char *address, int cardIndex); // The call to get the MAC address.
     const char* GetErrorMessage() {return m_error;}; // Returns the most recent error (should only be called after a function fails)
 
     static void CopyAddressToString(unsigned char hexAddr[6], char *strAddr);
 
     // These will be called automatically, but are public in case you would like to
     // unload the DLLs before this object goes out of scope.
     bool InitializeSNMP();  
     void UnInitializeSNMP();
     bool InitializeNetBIOS();  
     void UnInitializeNetBIOS();
     bool InitializeGuid();  
     void UnInitializeGuid();
 
protected:
     // function pointers for SNMP and winsock
     t_SnmpExtensionInit m_ptrSnmpExtensionInit;
     t_SnmpExtensionQuery m_ptrSnmpExtensionQuery;
     t_SnmpUtilOidCpy m_ptrSnmpUtilOidCpy;
     t_WSAStartup m_ptrWSAStartup;
     t_WSACleanup m_ptrWSACleanup;
 
     // dll handles for SNMP and winsock
     HINSTANCE m_snmpApiDll;
     HINSTANCE m_inetDll;
     HINSTANCE m_wsockDll;
     bool m_snmpInitialized;
 
     // function pointer for Netbios
     bool m_netbiosInitialized;
     HINSTANCE m_netbiosDll;
     t_Netbios m_ptrNetbios;
 
     //function pointer for UuidCreate
     bool m_uuidInitialized;
     HINSTANCE m_uuidDll;
     t_UuidCreate m_ptrUuidCreate;
 
     char m_error[256];   //   This string will contain an error message if any function fails.
 
};
 
Source File starts here.
__________________________________________________________________________
 
/* MacRetriever.cpp
* Author: Peter Donahue
* Contact (709) 891-1129 (ask for Peter)
* peter.donahue@comdev.ca
* techinterface@yahoo.ca
*
* This class simplifies the task of retrieving the MAC address of a particular
* card under MS Windows.
*/
 
// Uncomment this line if you are using VC++ precompiled headers through stdafx.h.
//#include "stdafx.h"
#include "MacRetriever.h"
 
CMacRetriever::CMacRetriever(void){
     m_ptrSnmpExtensionInit=NULL;
     m_ptrSnmpExtensionQuery=NULL;
     m_ptrSnmpUtilOidCpy=NULL;
     m_ptrWSAStartup=NULL;
     m_ptrWSACleanup=NULL;
 
     m_snmpApiDll=NULL;
     m_inetDll=NULL;
     m_wsockDll=NULL;
     m_snmpInitialized=false;
 
     m_ptrNetbios=NULL;
     m_netbiosDll=NULL;
     m_netbiosInitialized=false;
 
     m_ptrUuidCreate=NULL;
     m_uuidDll=NULL;
     m_uuidInitialized=false;
}
 
CMacRetriever::~CMacRetriever(void){
     UnInitializeSNMP();
     UnInitializeNetBIOS();
     UnInitializeGuid();
}
 
// Address must be at least 13 characters long.
bool CMacRetriever::GetMacUsingSNMP(char *address, int cardIndex){
 
     // This function used to be implemented using GUID, but that approach doesn't work
     // for Win2000...   This new approach uses SNMP.   Hopefully it will be a little more
     // robust.
     address[0]='\0';
     if (!InitializeSNMP()) return false;
 
     // Get the <addressNum> MAC address
     long errorStatus=0;
     long errorIndex=0;
     SnmpVarBindList bindList;
     SnmpVarBind bindVar;
     AsnObjectIdentifier tmpName;
     memset(&bindVar, 0, sizeof(bindVar));
     memset(&bindVar, 0, sizeof(bindList));
 
     bindList.len=1;
     bindList.list=&bindVar;
 
     const UINT MAC_ADDRESS_OID[] = {1, 3, 6, 1, 2, 1, 2, 2, 1, 6};
     tmpName.idLength=10;
     tmpName.ids=(UINT*)MAC_ADDRESS_OID;
 
     m_ptrSnmpUtilOidCpy(&bindVar.name, &tmpName);
 
     for(int i=0;i<cardIndex;++i){
          if (!m_ptrSnmpExtensionQuery(ASN_RFC1157_GETNEXTREQUEST, &bindList, &errorStatus, &errorIndex)){
               strcpy(m_error, "Error getting address from SNMP");
               return false;
          }
     }
 

     // bindVar should now have the address.
     unsigned char *addr=bindVar.value.asnValue.address.stream;
     if (!addr || addr==(UCHAR*)1){
          strcpy(m_error, "No address found at this index");
          return false;
     }
 
     // Copy addr into address
     address[0]='\0';
     CopyAddressToString(addr,address);
     return true;
 
}
 
void CMacRetriever::UnInitializeSNMP(void){
     if (m_ptrWSACleanup) m_ptrWSACleanup();
     if (m_inetDll) FreeLibrary(m_inetDll);
     if (m_snmpApiDll) FreeLibrary(m_snmpApiDll);
     if (m_wsockDll) FreeLibrary(m_wsockDll);
 
     m_ptrWSACleanup=NULL;
     m_inetDll=NULL;
     m_snmpApiDll=NULL;
     m_wsockDll=NULL;
 
     m_snmpInitialized=false;
}
 
// Load the SNMP and winsock dlls and get the required function pointers.
bool CMacRetriever::InitializeSNMP(void){
 
     if (m_snmpInitialized) return true;
 
     // Load DLLs
     m_wsockDll=LoadLibrary("ws2_32.dll");
     if (!m_wsockDll){
          strcpy(m_error,"Unable to load inetmib1.dll (SNMP dll)");
          return false;
     }
 
     m_inetDll = LoadLibrary("inetmib1.dll");
     if (!m_inetDll){
          strcpy(m_error,"Unable to load inetmib1.dll (SNMP dll)");
          return false;
     }
 
     m_snmpApiDll=LoadLibrary("snmpapi.dll");
     if (!m_snmpApiDll){
          strcpy(m_error,"Unable to load snmpapi.dll (SNMP dll)");
          return false;
     }
    
     // Get the SNMP function pointers.
     m_ptrSnmpExtensionInit=(t_SnmpExtensionInit)::GetProcAddress(m_inetDll, "SnmpExtensionInit");
     m_ptrSnmpExtensionQuery=(t_SnmpExtensionQuery)::GetProcAddress(m_inetDll, "SnmpExtensionQuery");
     m_ptrSnmpUtilOidCpy=(t_SnmpUtilOidCpy)::GetProcAddress(m_snmpApiDll, "SnmpUtilOidCpy");
    
     if (!m_ptrSnmpExtensionInit || !m_ptrSnmpExtensionQuery
          || !m_ptrSnmpUtilOidCpy){
          strcpy(m_error, "Error getting functions from SNMP dll.   You may not have the correct version of SNMP installed.");
          return false;
     }
 
     // Get the winsock pointers.
     m_ptrWSAStartup=(t_WSAStartup)::GetProcAddress(m_wsockDll, "WSAStartup");
     m_ptrWSACleanup=(t_WSACleanup)::GetProcAddress(m_wsockDll, "WSACleanup");
     if (!m_ptrWSAStartup || !m_ptrWSACleanup){
          strcpy(m_error, "Error getting functions from winsock dll.   Your winsock libs may not be installed properly.");
          // Set to null so they won't be called from UnInitialize
          m_ptrWSACleanup=NULL;
          return false;
     }
 
     // Call init routine for winsock.
     WSADATA sockData;
     if (m_ptrWSAStartup(MAKEWORD(2, 0), &sockData)){
          strcpy(m_error,"Winsock init failed.");
          m_ptrWSACleanup=NULL;
          return false;
     }
 
     // Call init routine for SNMP
     HANDLE eventTrap;
     AsnObjectIdentifier id;
     if (!m_ptrSnmpExtensionInit(0, &eventTrap, &id)){
          strcpy(m_error, "SNMP init failed.");
          return false;
     }
 
     m_snmpInitialized=true;
     return true;
}
 
typedef struct tagASTAT{
      ADAPTER_STATUS adapt;
      NAME_BUFFER      NameBuff [30];
}ASTAT;
 
//   This function can only handle a single address for the machine.
bool CMacRetriever::GetMacUsingGuid(char *address, int cardIndex){
 
     if (!InitializeGuid()) return false;
 
     address[0]='\0';
     if (cardIndex){
          strcpy(m_error, "CardIndex must be 0 when calling GetMacUsingGuid.   If you need other MACs use GetMacUsingNetBIOS or GetMacUsingSNMP.");
          return false;
     }
 
      UUID uuid;
     if (m_ptrUuidCreate(&uuid) != RPC_S_OK){
          strcpy(m_error, "UuidCreate returned an invalid GUID");
          return false;
     }
 
     CopyAddressToString(&uuid.Data4[2], address);
 
      return true;
}
 
bool CMacRetriever::GetMacUsingNetBIOS(char *address, int cardIndex){
 
     // Taken from MSDN article on finding the MAC address through NetBios.
     address[0]='\0';
     if (!InitializeNetBIOS()) return false;
 
     NCB ncb;
     ASTAT Adapter;
     memset(&ncb,0,sizeof(ncb));
     ncb.ncb_command=NCBRESET;
     ncb.ncb_lana_num=cardIndex;
     if (m_ptrNetbios(&ncb) != NRC_GOODRET){
          switch(ncb.ncb_retcode){
               case 0x23:
                    strcpy(m_error, "No NetBIOS interface found at this index");
                    break;
               default:
                    strcpy(m_error, "Error calling NetBIOS reset function");
          }
          return false;
     }
 
     memset(&ncb,0,sizeof(ncb));
     ncb.ncb_command=NCBASTAT;
     ncb.ncb_lana_num=cardIndex;
     strcpy((char*)ncb.ncb_callname,"*                     ");
     ncb.ncb_buffer=(unsigned char*)&Adapter;
     ncb.ncb_length=sizeof(Adapter);
     if (m_ptrNetbios(&ncb) != NRC_GOODRET){
          strcpy(m_error, "MAC address retrieval from NetBIOS failed");
          return false;
     }
 
     CopyAddressToString(Adapter.adapt.adapter_address, address);    
     return true;
}
 
void CMacRetriever::CopyAddressToString(unsigned char hexAddr[6], char *strAddr){
     char tmp[3];
 
     strAddr[0]='\0';
     for(int i=0;i<6;++i){
          itoa(hexAddr[i], tmp, 16);
          if (hexAddr[i] <= 0x0f) strcat(strAddr, "0");
          strcat(strAddr, tmp);
     }
}
 
void CMacRetriever::UnInitializeNetBIOS(void){
     if (m_netbiosDll) FreeLibrary(m_netbiosDll);
     m_netbiosDll=NULL;
     m_netbiosInitialized=false;
}
 
bool CMacRetriever::InitializeNetBIOS(void){
 
     if (m_netbiosInitialized) return true;
 
     // Load DLLs
     m_netbiosDll=LoadLibrary("Netapi32.dll");
     if (!m_netbiosDll){
          strcpy(m_error,"Unable to load Netapi32.dll (Netbios dll)");
          return false;
     }
 
     // Get the NetBIOS function pointer.
     m_ptrNetbios=(t_Netbios)::GetProcAddress(m_netbiosDll, "Netbios");
    
     if (!m_ptrNetbios){
          strcpy(m_error, "Error getting function from NetBIOS dll");
          return false;
     }
 
     m_netbiosInitialized=true;
 
     return true;
}
 
void CMacRetriever::UnInitializeGuid(void){
     if (m_uuidDll) FreeLibrary(m_uuidDll);
     m_uuidDll=NULL;
     m_uuidInitialized=false;
}
 
bool CMacRetriever::InitializeGuid(void){
 
     // We need a function to return a valid GUID (UUID including MAC address)
     if (m_uuidInitialized) return true;
 
     // Load DLLs
     m_uuidDll=LoadLibrary("rpcrt4.dll");
     if (!m_uuidDll){
          strcpy(m_error,"Unable to load rpcrt.dll (RPC dll for UuidCreate)");
          return false;
     }
 
     // Get the UuidCreate function pointer.
     m_ptrUuidCreate=(t_UuidCreate)::GetProcAddress(m_uuidDll, "UuidCreateSequential");
     if (!m_ptrUuidCreate){
          // We may be on an older OS.   Try to get old function
          m_ptrUuidCreate=(t_UuidCreate)::GetProcAddress(m_uuidDll, "UuidCreate");
     }
     if (!m_ptrUuidCreate){
          strcpy(m_error, "Error getting UuidCreate function from rpcrt4.dll");
          return false;
     }
 
     m_uuidInitialized=true;
 
     return true;
}
 
Test Program starts here.
____________________________________________________________________________
#include "MacRetriever.h"
#include <stdio.h>
 
int main(){
 
     CMacRetriever mac;
     int i;
     char address[13];
     printf("SNMP:\n");
     for(i=0;i<6;++i){
          if (mac.GetMacUsingSNMP(address,i)){
               printf("mac address: %s\n", address);
          }else{
               printf("Error: %s\n", mac.GetErrorMessage());
          }
     }
 
     printf("\nNetBIOS:\n");
     for(i=0;i<6;++i){
          if (mac.GetMacUsingNetBIOS(address,i)){
               printf("mac address: %s\n", address);
          }else{
               printf("Error: %s\n", mac.GetErrorMessage());
          }
     }
 
     printf("\nGUID:\n");
     for(i=0;i<6;++i){
          if (mac.GetMacUsingGuid(address,i)){
               printf("mac address: %s\n", address);
          }else{
               printf("Error: %s\n", mac.GetErrorMessage());
          }
     }
 
#ifdef _DEBUG
     Sleep(10000);
#endif
}
 

 
____________________________
Peter Donahue
Code Monkey
COM DEV International R&D
Cambridge, ON, Canada

GeneralVery very good job. PinmemberVCPP619:25 15 Nov '04  
GeneralRe: MAC from multiple sources. Pinmembersizheng23:30 6 Jul '05  

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

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

Permalink | Advertise | Privacy | Mobile
Web01 | 2.5.120529.1 | Last Updated 12 May 2002
Article Copyright 2001 by Ryszard Krakowiak
Everything else Copyright © CodeProject, 1999-2012
Terms of Use
Layout: fixed | fluid