【转载】获取MAC地址方法大全
From:http://blog.csdn.net/han2814675/article/details/6223617
Windows平台下用C++代码取得机器的MAC地址并不是一件简单直接的事情。到目前为止,作者尚未发现有任何一个通用的100%的适用于所有Windows平台的方法可以稳定的取得MAC地址。而有些应用(比如MMORPG)则需要稳定的得到机器的MAC地址,解决方案往往是通过多种方法依次使用来提高成功率。
- 以下方法只会返回多网卡的第一个MAC地址。
- 网上有很多文章和源码来解决该问题,大多不全或有问题。本篇所有方法均经过整理调试,可直接使用。
- 作者也不喜欢满篇帖代码,本篇贴代码是方便直接使用,请读者谅解。
#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);// 取得MACfor (int i = 0; i < adapterList.length; ++i){if (GetAdapterInfo(adapterList.lana[i], macOUT))return true;}return false;}
#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来提取MACbool 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;}
#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 necessaryconst 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_SnmpExtensionQueryconst 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 tablevarBindList.len = 1; // Only retrieving one itemSnmpUtilOidCpy(&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 interfaceSnmpUtilOidCpy(&varBind[0].name, &MIB_ifEntryType);// Copy in the OID of ifPhysAddress, the addressSnmpUtilOidCpy(&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 systemif(f_SnmpExtensionQuery(ASN_RFC1157_GETNEXTREQUEST, &varBindList, &errorStatus, &errorIndex) == FALSE)continue;// Confirm that the proper type has been returnedif(SnmpUtilOidNCmp(&varBind[0].name, &MIB_ifEntryType, MIB_ifEntryType.idLength) != 0)continue;// Type 6 describes ethernet interfacesif(varBind[0].value.asnValue.number != 6)continue;// Confirm that we have an address hereif(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 adaptersif ((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 interfacesif ((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 bindingsSnmpUtilVarBindFree(&varBind[0]);SnmpUtilVarBindFree(&varBind[1]);return ret;}
#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 variableif(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-00if(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;}
#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 variableif(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 receivedfor(PIP_ADAPTER_ADDRESSES pCurrAddresses = pAddresses; pCurrAddresses != NULL; pCurrAddresses = pCurrAddresses->Next){// 确保MAC地址的长度为 00-00-00-00-00-00if(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地址方法大全的更多相关文章
- 获取mac地址方法之一 GetAdaptersInfo()
GetAdaptersInfo -20151116 防止返回的mac出现null 20151116 From:http://blog.csdn.net/weiyumingwww/article/det ...
- android获取mac地址方法
http://www.cnblogs.com/xioapingguo/p/4037513.html 网上找的,记录一下 public static String getMacAdress(){ Wif ...
- dotnet core 获取 MacAddress 地址方法
本文告诉大家如何在 dotnet core 获取 Mac 地址 因为在 dotnetcore 是没有直接和硬件相关的,所以无法通过 WMI 的方法获取当前设备的 Mac 地址 但是在 dotnet c ...
- 【转载】VC获取MAC地址的4种方法
From:http://blog.csdn.net/pdfmaker/article/details/465748 有需求才有创造,有了问题才会想着去解决,那么我这里的获取MAC地址的第4种方法也是在 ...
- [记]WIndow/Linux 获取本机(全部)IPv4、IPv6、MAC地址方法 (C/C++)
Linux 获取本机IP.MAC地址用法大全 //#include <sys/types.h> #include <ifaddrs.h> #include <sys/io ...
- Linux 获取本机IP、MAC地址用法大全
getifaddrs()和struct ifaddrs的使用,获取本机IP ifaddrs结构体定义如下: struct ifaddrs { struct ifaddrs *ifa_next; /* ...
- C#获取MAC地址的几种方法
首先需要用到的一些方法和类: public enum NCBCONST { NCBNAMSZ = 16, MAX_LANA = 254, NCBENUM = 0x37, NRC_GOODRET = 0 ...
- C#获取IP及MAC地址 方法
C#获取IP及MAC地址 方法,比较齐全 using System.Net; using System; using System.Management; using System.Runtime.I ...
- (转)【Android】获取Mac地址【2】
[Android]获取Mac地址[2] 之前写了[Android]获取Mac地址[1]有些不够详细,现在贴上一些其他代码,仅供参考. (1) 调用android 的API: NetworkInterf ...
随机推荐
- hibernate validator 验证
@AssertTrue 用于boolean字段,该字段只能为true @AssertFalse 该字段的值只能为false @CreditCardNumber 对信用卡号进行一个大致的验证 @De ...
- PAT 天梯赛 L1-018. 大笨钟 【水】
题目链接 https://www.patest.cn/contests/gplt/L1-018 AC代码 #include <iostream> #include <cstdio&g ...
- Libev和LibEvent
libev和libevent功能基本相同,名称相近,到底该用哪一个呢?zhouhh@zhh64:~$ sudo apt-cache search libeventlibevent-dev – Deve ...
- ExtJS + fileuploadfield实现文件上传
后台服务端接收文件的代码: /** * 后台上传文件处理Action */ @RequestMapping(value = "/uploadFile", method=Reques ...
- WPF MVVM模式下ComboBox级联效果 选择第一项
MVVM模式下做的省市区的级联效果.通过改变ComboBox执行命令改变市,区. 解决主要问题就是默认选中第一项 1.首先要定义一个属性,继承自INotifyPropertyChanged接口.我这里 ...
- Android 电池关机充电
android 电池(一):锂电池基本原理篇 android 电池(二):android关机充电流程.充电画面显示 android 电池(三):android电池系统 android电池(四):电池 ...
- 多线程、多进程、协程、IO多路复用请求百度
最近学习了多线程.多进程.协程以及IO多路复用,那么对于爬取数据来说,这几个方式哪个最快呢,今天就来稍微测试一下 普通方式请求百度5次 import socket import time import ...
- nginx重新加载配置(不停服)
RT,改变配置想让它生效而不停止服务,如下两种方式都可以: 1) nginx -t; nginx -s reload2) nginx -t; kill -HUP
- C语言排序算法之简单交换法排序,直接选择排序,冒泡排序
C语言排序算法之简单交换法排序,直接选择排序,冒泡排序,最近考试要用到,网上也有很多例子,我觉得还是自己写的看得懂一些. 简单交换法排序 /*简单交换法排序 根据序列中两个记录键值的比较结果来对换这两 ...
- SpringCloud之eureka服务注册和服务发现
服务注册中心 :eureka-server 作用:服务注册中心提供服务注册功能 服务提供方:eureka-client 作用:注册服务到服务注册中心 服务注册中心 :eureka-server 创建 ...