This example shows you how to use the NetBIOS API to retrieve the MAC addresses of the network adapters in a system. There are two weaknesses to this approach. The first is that you have to have the NetBEUI protocol installed and bound to the network adapter whose address you want. The second is that if you have more than one network adapter, you may have to do extra work to figure out which address you really want. If these weaknesses are a problem, you might look at the RPC variation for getting the MAC address.
Note that there is a line below that reads "Ncb.ncb_buffer = (unsigned char*)&Adapter" under MSIE 3.0, due to a bug in their rendering engine that I seem to be unable to work around. This line does properly show a semicolon at the end under Navigator. (If anyone has some fun HTML tricks that will work around this problem, please let me know. Know, however that I think I've tried all the obvious and even some less obvious tricks.)
This code is based on that presented in Microsoft Knowledge Base article Q118623. Of course, my code is cleaner and smarter than theirs is. B-)
// Visual C++ 5.0: cl -GX getmac-netbios.cpp netapi32.lib // Borland C++ 5.0: bcc32 getmac-netbios.cpp #include <windows.h> #include <stdlib.h> #include <stdio.h> #include <iostream> #include <strstream> #include <string> using namespace std; bool GetAdapterInfo(int nAdapterNum, string& sMAC) { // Reset the LAN adapter so that we can begin querying it NCB Ncb; memset(&Ncb, 0, sizeof(Ncb)); Ncb.ncb_command = NCBRESET; Ncb.ncb_lana_num = nAdapterNum; if (Netbios(&Ncb) != NRC_GOODRET) { char acTemp[80]; ostrstream outs(acTemp, sizeof(acTemp)); outs << "error " << Ncb.ncb_retcode << " on reset" << ends; sMAC = acTemp; return false; } // Prepare to get the adapter status block memset(&Ncb, 0, sizeof(Ncb)); Ncb.ncb_command = NCBASTAT; Ncb.ncb_lana_num = nAdapterNum; strcpy((char*)Ncb.ncb_callname, "*"); struct ASTAT { ADAPTER_STATUS adapt; NAME_BUFFER NameBuff[30]; } Adapter; memset(&Adapter, 0, sizeof(Adapter)); Ncb.ncb_buffer = (unsigned char*)&Adapter; Ncb.ncb_length = sizeof(Adapter); // Get the adapter's info and, if this works, return it in standard, // colon-delimited form. if (Netbios(&Ncb) == 0) { char acMAC[18]; sprintf(acMAC, "%02X:%02X:%02X:%02X:%02X:%02X", int(Adapter.adapt.adapter_address[0]), int(Adapter.adapt.adapter_address[1]), int(Adapter.adapt.adapter_address[2]), int(Adapter.adapt.adapter_address[3]), int(Adapter.adapt.adapter_address[4]), int(Adapter.adapt.adapter_address[5])); sMAC = acMAC; return true; } else { char acTemp[80]; ostrstream outs(acTemp, sizeof(acTemp)); outs << "error " << Ncb.ncb_retcode << " on ASTAT" << ends; sMAC = acTemp; return false; } } void main() { // Get adapter list LANA_ENUM AdapterList; NCB Ncb; memset(&Ncb, 0, sizeof(NCB)); Ncb.ncb_command = NCBENUM; Ncb.ncb_buffer = (unsigned char*)&AdapterList; Ncb.ncb_length = sizeof(AdapterList); Netbios(&Ncb); // Get all of the local ethernet addresses string sMAC; for (int i = 0; i < AdapterList.length - 1; ++i) { if (GetAdapterInfo(AdapterList.lana[i], sMAC)) { cout << "Adapter " << int(AdapterList.lana[i]) << "'s MAC is " << sMAC << endl; } else { cerr << "Failed to get MAC address! Do you" << endl; cerr << "have the NetBIOS protocol installed?" << endl; break; } } }
Back to the Advanced Issues page...
Back to the Examples page...
![]() |
Go to my home page |
![]() |
Go to my Important RFC Lists page |
![]() |
Go to the main Programming Resources page |
Please send updates and corrections to <tangent@cyberport.com>.