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. web标准的理解

    首先,什么是web标准?web标准是w3c组织为解决跨浏览器兼容问题而推出的关于网页开发时应遵守的规范.在网页的四个部分中网页的内容是由网页开发者自己定义的,因此这一部分无法标准化,而网页的结构(HT ...

  2. CSS的单位 及 css3的calc() 及 line-height 百分比

    CSS的单位及css3的calc()及line-height百分比 摘自:http://www.haorooms.com/post/css_unit_calc 单位介绍 说到css的单位,大家应该首先 ...

  3. mfc报文相关算法

    1.传入_T("AAAABBBBCC"),返回_T("AA AA BB BB CC") CString FormatPacket(CString packet_ ...

  4. Makefile的简单编写【学习笔记】

    首先我们先创建两个简单的文件: main.c #include <stdio.h> extern void hi_fun(); int main() { printf("hell ...

  5. Linux系统下wget命令的使用教程

    一.Linux wget简介 wget是linux上的命令行的下载工具.这是一个GPL许可证下的自由软件.Linux wget支持HTTP和FTP协议,支持代理服务器和断点续传功能,能够自动递归远程主 ...

  6. What's the difference between UTF-8 and UTF-8 without BOM?

    https://stackoverflow.com/questions/2223882/whats-the-difference-between-utf-8-and-utf-8-without-bom ...

  7. RAID独立冗余磁盘阵列

    独立冗余磁盘阵列(Redundant Array OF Independent Disks,RAID)开始于20世纪80年代美国加州大学伯克利分校的一个研究项目,当时RAID被称为廉价冗余磁盘阵列(R ...

  8. JAVA实现IP地址解析

    转载至:http://blog.csdn.net/dragontang/article/details/4151660 http://www.iteye.com/topic/340548#

  9. lastIndexOf 方法 (Array) (JavaScript)

    lastIndexOf 方法 (Array) (JavaScript) 返回指定的值在数组中的最后一个匹配项的索引. 语法         array1.lastIndexOf(searchEleme ...

  10. struts2——上传图片格式

    <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding= ...