From:http://blog.csdn.net/han2814675/article/details/6223617

Windows平台下用C++代码取得机器的MAC地址并不是一件简单直接的事情。到目前为止,作者尚未发现有任何一个通用的100%的适用于所有Windows平台的方法可以稳定的取得MAC地址。而有些应用(比如MMORPG)则需要稳定的得到机器的MAC地址,解决方案往往是通过多种方法依次使用来提高成功率。

            说明:
    • 以下方法只会返回多网卡的第一个MAC地址。
    • 网上有很多文章和源码来解决该问题,大多不全或有问题。本篇所有方法均经过整理调试,可直接使用。
    • 作者也不喜欢满篇帖代码,本篇贴代码是方便直接使用,请读者谅解。
    下面奉上几种常用的方法:

方法一:通过NetBIOS
    [Netbios is not supported on Windows Vista, Windows Server 2008, and subsequent versions of the operating system]
 
#include <windows.h>
#pragma comment(lib, "Netapi32.lib")
 
namespace
{
bool GetAdapterInfo(int adapterNum, std::string& macOUT)
{
NCB Ncb;
memset(&Ncb, 0, sizeof(Ncb));
Ncb.ncb_command = NCBRESET; // 重置网卡,以便我们可以查询
Ncb.ncb_lana_num = adapterNum;
if (Netbios(&Ncb) != NRC_GOODRET)
return false;
 
// 准备取得接口卡的状态块
memset(&Ncb, sizeof(Ncb), 0);
Ncb.ncb_command = NCBASTAT;
Ncb.ncb_lana_num = adapterNum;
strcpy((char *) Ncb.ncb_callname, "*");
struct ASTAT
{
ADAPTER_STATUS adapt;
NAME_BUFFER nameBuff[30];
}adapter;
memset(&adapter,sizeof(adapter), 0);
Ncb.ncb_buffer = (unsigned char *)&adapter;
Ncb.ncb_length = sizeof(adapter);
if (Netbios(&Ncb) != 0)
return false;
 
char acMAC[32];
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]));
macOUT = acMAC;
return true;
}
}
 
bool GetMacByNetBIOS(std::string& macOUT)
{
// 取得网卡列表
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);
 
// 取得MAC
for (int i = 0; i < adapterList.length; ++i)
{
if (GetAdapterInfo(adapterList.lana[i], macOUT))
return true;
}
 
return false;
}
 
参考:


方法二:通过对控制台ipconfig /all命令重定向
#include <Windows.h>
#include <boost/regex.hpp>
 
namespace
{
#if 0
/// @brief 采用字符串查找来提取MAC地址
/// @remark 该方法有很大局限性,并不是所有OS返回的MAC地址前导字符串都是
///     "Physical Address. . . . . . . . . : "
bool ParseMac(const std::string& str, std::string& macOUT)
{
static const std::string beginMarkOfMAC("Physical Address. . . . . . . . . : ");
static const std::string endMarkOfMAC("/r/n");
size_t begin = str.find(beginMarkOfMAC);
if(begin != std::string::npos)
{
begin += beginMarkOfMAC.size();
size_t end = str.find(endMarkOfMAC, begin);
if(end != std::string::npos)
{
macOUT = str.substr(begin, end - begin - 1);
return true;
}
}
return false;
}
#else
/// @brief 采用boost::regex来提取MAC
bool ParseMac(const std::string& str, std::string& macOUT)
{
const static boost::regex expression(
"([0-9a-fA-F]{2})-([0-9a-fA-F]{2})-([0-9a-fA-F]{2})-([0-9a-fA-F]{2})-([0-9a-fA-F]{2})-([0-9a-fA-F]{2})", 
boost::regex::perl | boost::regex::icase);
boost::cmatch what; 
if(boost::regex_search(str.c_str(), what, expression)) 
{
macOUT = what[1] + "-" + what[2] + "-" + what[3] + "-" + what[4] + "-" + what[5] + "-" + what[6];
return true;
}
return false;
}
#endif
}
 
bool GetMacByCmd(std::string& macOUT)
{
bool ret = false;
 
//初始化返回MAC地址缓冲区
SECURITY_ATTRIBUTES sa; 
sa.nLength = sizeof(SECURITY_ATTRIBUTES); 
sa.lpSecurityDescriptor = NULL; 
sa.bInheritHandle = TRUE; 
 
//创建管道
HANDLE hReadPipe,hWritePipe;
if(CreatePipe(&hReadPipe, &hWritePipe, &sa, 0) == TRUE)
{
//控制命令行窗口信息
STARTUPINFO si; 
//返回进程信息
PROCESS_INFORMATION pi;
si.cb = sizeof(STARTUPINFO); 
GetStartupInfo(&si); 
si.hStdError = hWritePipe; 
si.hStdOutput = hWritePipe; 
si.wShowWindow = SW_HIDE; //隐藏命令行窗口
si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
 
//创建获取命令行进程
if (CreateProcess(NULL, "ipconfig /all", NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi) == TRUE) 
WaitForSingleObject(pi.hProcess, 3000); // 设置超时时间,防止Vista、Win7等操作系统卡死
unsigned long count;
CloseHandle(hWritePipe);
std::string strBuffer(1024 * 10, '/0'); // 准备足够大的缓冲区
if(ReadFile(hReadPipe, const_cast<char*>(strBuffer.data()), strBuffer.size() - 1, &count, 0) == TRUE)
{
strBuffer.resize(strBuffer.find_first_of('/0')); // 截掉缓冲区后面多余的'/0'
ret = ParseMac(strBuffer, macOUT);//提取MAC地址串
}
CloseHandle(pi.hThread); 
CloseHandle(pi.hProcess); 
}
CloseHandle(hWritePipe); // VS2010下调试,此处会有“An invalid handle was specified”的中断,直接运行正常,原因未知。VS2008上正常。
CloseHandle(hReadPipe);
}
return ret;
}
 
参考:
方法三:通过SNMP(简单网络访问协议)
#include <snmp.h>
#pragma comment(lib, "snmpapi.lib")
#pragma comment(lib, "Ws2_32.lib")
 
bool GetMacBySNMP(std::string& macOUT)
{
bool ret = false;
WSADATA WinsockData;
if (WSAStartup(MAKEWORD(2, 0), &WinsockData) != 0) 
return false;
 
// Load the SNMP dll and get the addresses of the functions necessary
const HINSTANCE m_dll = LoadLibrary("inetmib1.dll");
if (m_dll < (HINSTANCE) HINSTANCE_ERROR)
return false;
 
const PFNSNMPEXTENSIONINIT f_SnmpExtensionInit = (PFNSNMPEXTENSIONINIT) GetProcAddress(m_dll, "SnmpExtensionInit");
const PFNSNMPEXTENSIONINITEX f_SnmpExtensionInitEx = (PFNSNMPEXTENSIONINITEX) GetProcAddress(m_dll, "SnmpExtensionInitEx");
const PFNSNMPEXTENSIONQUERY f_SnmpExtensionQuery = (PFNSNMPEXTENSIONQUERY) GetProcAddress(m_dll, "SnmpExtensionQuery");
const PFNSNMPEXTENSIONTRAP f_SnmpExtensionTrap = (PFNSNMPEXTENSIONTRAP) GetProcAddress(m_dll, "SnmpExtensionTrap");
 
HANDLE pollForTrapEvent;
AsnObjectIdentifier supportedView;
f_SnmpExtensionInit(GetTickCount(), &pollForTrapEvent, &supportedView);
 
// Initialize the variable list to be retrieved by f_SnmpExtensionQuery
const AsnObjectIdentifier MIB_NULL = { 0, 0 };
 
RFC1157VarBind varBind[2];
varBind[0].name = MIB_NULL;
varBind[1].name = MIB_NULL;
 
RFC1157VarBindList varBindList;
varBindList.list = varBind;
 
UINT OID_ifEntryType[] = { 1, 3, 6, 1, 2, 1, 2, 2, 1, 3 };
UINT OID_ifEntryNum[] = { 1, 3, 6, 1, 2, 1, 2, 1 };
UINT OID_ipMACEntAddr[] = { 1, 3, 6, 1, 2, 1, 2, 2, 1, 6 };
AsnObjectIdentifier MIB_ifMACEntAddr = { sizeof(OID_ipMACEntAddr) / sizeof(UINT), OID_ipMACEntAddr };
AsnObjectIdentifier MIB_ifEntryType = { sizeof(OID_ifEntryType) / sizeof(UINT), OID_ifEntryType };
AsnObjectIdentifier MIB_ifEntryNum = { sizeof(OID_ifEntryNum) / sizeof(UINT), OID_ifEntryNum };
 
// Copy in the OID to find the number of entries in the Inteface table
varBindList.len = 1;        // Only retrieving one item
SnmpUtilOidCpy(&varBind[0].name, &MIB_ifEntryNum);
AsnInteger errorStatus;
AsnInteger errorIndex;
f_SnmpExtensionQuery(ASN_RFC1157_GETNEXTREQUEST, &varBindList, &errorStatus, &errorIndex);
varBindList.len = 2;
 
// Copy in the OID of ifType, the type of interface
SnmpUtilOidCpy(&varBind[0].name, &MIB_ifEntryType);
 
// Copy in the OID of ifPhysAddress, the address
SnmpUtilOidCpy(&varBind[1].name, &MIB_ifMACEntAddr);
 
for(int j = 0; j < varBind[0].value.asnValue.number; j++)
{
// Submit the query.  Responses will be loaded into varBindList.
// We can expect this call to succeed a # of times corresponding to the # of adapters reported to be in the system
if(f_SnmpExtensionQuery(ASN_RFC1157_GETNEXTREQUEST, &varBindList, &errorStatus, &errorIndex) == FALSE)
continue;
// Confirm that the proper type has been returned
if(SnmpUtilOidNCmp(&varBind[0].name, &MIB_ifEntryType, MIB_ifEntryType.idLength) != 0)
continue;
// Type 6 describes ethernet interfaces
if(varBind[0].value.asnValue.number != 6) 
continue;
// Confirm that we have an address here
if(SnmpUtilOidNCmp(&varBind[1].name, &MIB_ifMACEntAddr, MIB_ifMACEntAddr.idLength) != 0)
continue;
if(varBind[1].value.asnValue.address.stream == NULL)
continue;
// Ignore all dial-up networking adapters
if ((varBind[1].value.asnValue.address.stream[0] == 0x44)
&& (varBind[1].value.asnValue.address.stream[1] == 0x45)
&& (varBind[1].value.asnValue.address.stream[2] == 0x53)
&& (varBind[1].value.asnValue.address.stream[3] == 0x54)
&& (varBind[1].value.asnValue.address.stream[4] == 0x00)) 
continue;
// Ignore NULL addresses returned by other network interfaces
if ((varBind[1].value.asnValue.address.stream[0] == 0x00)
&& (varBind[1].value.asnValue.address.stream[1] == 0x00)
&& (varBind[1].value.asnValue.address.stream[2] == 0x00)
&& (varBind[1].value.asnValue.address.stream[3] == 0x00)
&& (varBind[1].value.asnValue.address.stream[4] == 0x00)
&& (varBind[1].value.asnValue.address.stream[5] == 0x00)) 
continue;
char buf[32];
sprintf(buf, "%02X-%02X-%02X-%02X-%02X-%02X",
varBind[1].value.asnValue.address.stream[0],
varBind[1].value.asnValue.address.stream[1],
varBind[1].value.asnValue.address.stream[2],
varBind[1].value.asnValue.address.stream[3],
varBind[1].value.asnValue.address.stream[4],
varBind[1].value.asnValue.address.stream[5]);
macOUT = buf;
ret = true;
break;
}
 
// Free the bindings
SnmpUtilVarBindFree(&varBind[0]);
SnmpUtilVarBindFree(&varBind[1]);
return ret;
}
方法四:通过GetAdaptersInfo函数(适用于Windows 2000及以上版本)
#include <winsock2.h>
#include <iphlpapi.h>
#pragma comment(lib, "IPHLPAPI.lib")
 
bool GetMacByGetAdaptersInfo(std::string& macOUT)
{
bool ret = false;
 
ULONG ulOutBufLen = sizeof(IP_ADAPTER_INFO);
PIP_ADAPTER_INFO pAdapterInfo = (IP_ADAPTER_INFO*)malloc(sizeof(IP_ADAPTER_INFO));
if(pAdapterInfo == NULL)
return false;
// Make an initial call to GetAdaptersInfo to get the necessary size into the ulOutBufLen variable
if(GetAdaptersInfo(pAdapterInfo, &ulOutBufLen) == ERROR_BUFFER_OVERFLOW) 
{
free(pAdapterInfo);
pAdapterInfo = (IP_ADAPTER_INFO *)malloc(ulOutBufLen);
if (pAdapterInfo == NULL) 
return false;
}
 
if(GetAdaptersInfo(pAdapterInfo, &ulOutBufLen) == NO_ERROR)
{
for(PIP_ADAPTER_INFO pAdapter = pAdapterInfo; pAdapter != NULL; pAdapter = pAdapter->Next)
{
// 确保是以太网
if(pAdapter->Type != MIB_IF_TYPE_ETHERNET)
continue;
// 确保MAC地址的长度为 00-00-00-00-00-00
if(pAdapter->AddressLength != 6)
continue;
char acMAC[32];
sprintf(acMAC, "%02X-%02X-%02X-%02X-%02X-%02X",
int (pAdapter->Address[0]),
int (pAdapter->Address[1]),
int (pAdapter->Address[2]),
int (pAdapter->Address[3]),
int (pAdapter->Address[4]),
int (pAdapter->Address[5]));
macOUT = acMAC;
ret = true;
break;
}
}
 
free(pAdapterInfo);
return ret;
}
 
参考:
 

方法五:通过GetAdaptersAddresses函数(适用于Windows XP及以上版本)
#include <winsock2.h>
#include <iphlpapi.h>
#pragma comment(lib, "IPHLPAPI.lib")
 
bool GetMacByGetAdaptersAddresses(std::string& macOUT)
{
bool ret = false;
 
ULONG outBufLen = sizeof(IP_ADAPTER_ADDRESSES);
PIP_ADAPTER_ADDRESSES pAddresses = (IP_ADAPTER_ADDRESSES*)malloc(outBufLen);
if (pAddresses == NULL) 
return false;
// Make an initial call to GetAdaptersAddresses to get the necessary size into the ulOutBufLen variable
if(GetAdaptersAddresses(AF_UNSPEC, 0, NULL, pAddresses, &outBufLen) == ERROR_BUFFER_OVERFLOW)
{
free(pAddresses);
pAddresses = (IP_ADAPTER_ADDRESSES*)malloc(outBufLen);
if (pAddresses == NULL) 
return false;
}
 
if(GetAdaptersAddresses(AF_UNSPEC, 0, NULL, pAddresses, &outBufLen) == NO_ERROR)
{
// If successful, output some information from the data we received
for(PIP_ADAPTER_ADDRESSES pCurrAddresses = pAddresses; pCurrAddresses != NULL; pCurrAddresses = pCurrAddresses->Next)
{
// 确保MAC地址的长度为 00-00-00-00-00-00
if(pCurrAddresses->PhysicalAddressLength != 6)
continue;
char acMAC[32];
sprintf(acMAC, "%02X-%02X-%02X-%02X-%02X-%02X",
int (pCurrAddresses->PhysicalAddress[0]),
int (pCurrAddresses->PhysicalAddress[1]),
int (pCurrAddresses->PhysicalAddress[2]),
int (pCurrAddresses->PhysicalAddress[3]),
int (pCurrAddresses->PhysicalAddress[4]),
int (pCurrAddresses->PhysicalAddress[5]));
macOUT = acMAC;
ret = true;
break;
}
 
free(pAddresses);
return ret;
}

【转载】获取MAC地址方法大全的更多相关文章

  1. 获取mac地址方法之一 GetAdaptersInfo()

    GetAdaptersInfo -20151116 防止返回的mac出现null 20151116 From:http://blog.csdn.net/weiyumingwww/article/det ...

  2. android获取mac地址方法

    http://www.cnblogs.com/xioapingguo/p/4037513.html 网上找的,记录一下 public static String getMacAdress(){ Wif ...

  3. dotnet core 获取 MacAddress 地址方法

    本文告诉大家如何在 dotnet core 获取 Mac 地址 因为在 dotnetcore 是没有直接和硬件相关的,所以无法通过 WMI 的方法获取当前设备的 Mac 地址 但是在 dotnet c ...

  4. 【转载】VC获取MAC地址的4种方法

    From:http://blog.csdn.net/pdfmaker/article/details/465748 有需求才有创造,有了问题才会想着去解决,那么我这里的获取MAC地址的第4种方法也是在 ...

  5. [记]WIndow/Linux 获取本机(全部)IPv4、IPv6、MAC地址方法 (C/C++)

    Linux 获取本机IP.MAC地址用法大全 //#include <sys/types.h> #include <ifaddrs.h> #include <sys/io ...

  6. Linux 获取本机IP、MAC地址用法大全

    getifaddrs()和struct ifaddrs的使用,获取本机IP ifaddrs结构体定义如下: struct ifaddrs { struct ifaddrs *ifa_next; /* ...

  7. C#获取MAC地址的几种方法

    首先需要用到的一些方法和类: public enum NCBCONST { NCBNAMSZ = 16, MAX_LANA = 254, NCBENUM = 0x37, NRC_GOODRET = 0 ...

  8. C#获取IP及MAC地址 方法

    C#获取IP及MAC地址 方法,比较齐全 using System.Net; using System; using System.Management; using System.Runtime.I ...

  9. (转)【Android】获取Mac地址【2】

    [Android]获取Mac地址[2] 之前写了[Android]获取Mac地址[1]有些不够详细,现在贴上一些其他代码,仅供参考. (1) 调用android 的API: NetworkInterf ...

随机推荐

  1. PAT 天梯赛 L1-045. 宇宙无敌大招呼 【水】

    题目链接 https://www.patest.cn/contests/gplt/L1-045 AC代码 #include <iostream> #include <cstdio&g ...

  2. PAT 天梯赛 L1-021. 重要的话说三遍 【水】

    题目链接 https://www.patest.cn/contests/gplt/L1-021 AC代码 #include <iostream> #include <cstdio&g ...

  3. Unity,如何阻塞当前函数一段时间

    public class Example : MonoBehaviour { IEnumerator Example() { print(Time.time); ); print(Time.time) ...

  4. shell自动化一键部署脚本,秒级一键回滚脚本

    #!/bin/bash # Node List PRE_LIST="192.168.222.163" # 预生产环境节点 GROUP1_LIST= ROLLBACK_LIST=&q ...

  5. 详解Linux系统下PXE服务器的部署过程

    在大规模安装服务器时,需要批量自动化方法来安装服务器,来减少日常的工作量. 但是批量自动化安装服务器的基础是网络启动服务器(bootserver). 下面我们就介绍一下 网络启动服务器的 安装和配置方 ...

  6. 使用MyCat分表分库原理分析

    Mycat可以实现 读写分离 分表分库 主从复制是MySQL自带的哈~ 关于分片取模算法:  根据id进行取模  根据数据库集群的数量(或者说是表数量,mycat里面一个表对应一个库) 使用MyCat ...

  7. install tabix/bgzip

    bgzip – Block compression/decompression utility tabix – Generic indexer for TAB-delimited genome pos ...

  8. Coundn't load memtrack module (No such file or directory)

    Coundn't load memtrack module (No such file or directory) 去仔细看日志,是包名有问题 一.出现症状 提示找logcat logcat里面发现C ...

  9. Android GridView 行间距过大(一页一行)

    1. gridView.xml中 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android&quo ...

  10. Ajax-08 跨域获取最新电视节目清单实例

    目标一 请求江西网络广播电视台电视节目 URL:http://www.jxntv.cn/data/jmd-jxtv2.html 分析 1.从Http头信息分析得知,器服务端未返回响应头Access-C ...