首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> 關於C++

Windows 取得網卡 MAC 位址三大法:NetBIOS、WMI/GUID、SNMP 深度比較

     編輯:關於C++

在 Windows 平台取得網路介面卡 MAC 位址,常見三種 API 路徑:**NetBIOS (傳統)、WMI/COM GUID (簡易但不可靠)、SNMP MIB (標準管理)**。本文詳細比較三者原理、適用場景、程式碼實作與優缺點,助您選擇最適合專案的方案。

方法一:NetBIOS API (NCBENUM + NCBASTAT)

優點:速度快、資訊完整 (含多張網卡)、無需 WMI 服務。
缺點:需啟用 NetBIOS over TCP/IP (現代 Windows 預設開啟);需連結 Netapi32.lib。

核心流程

  1. NCBENUM 列舉 LANA 番号 (邏輯介面編號)。
  2. 對每個 LANA NCBRESET 重置。
  3. NCBASTAT 查詢介面卡狀態,從 ADAPTER_STATUS.adapter_address 取得 6 位元組 MAC。

關鍵代碼 (精簡版)

#include <windows.h>
#include <netbios.h>
#pragma comment(lib, "netapi32.lib")

bool GetMacByNetBIOS(std::vector<std::string>& macs) {
    NCB ncb = {0};
    LANA_ENUM le; ncb.ncb_command = NCBENUM; ncb.ncb_buffer = (UCHAR*)≤ ncb.ncb_length = sizeof(le);
    if (Netbios(&ncb) != NRC_GOODRET) return false;

    for (int i = 0; i < le.length; ++i) {
        UCHAR lana = le.lana[i];
        // Reset
        ncb = {0}; ncb.ncb_command = NCBRESET; ncb.ncb_lana_num = lana;
        if (Netbios(&ncb) != NRC_GOODRET) continue;
        // ASTAT
        struct { ADAPTER_STATUS ad; NAME_BUFFER nb[30]; } ast;
        ncb = {0}; ncb.ncb_command = NCBASTAT; ncb.ncb_lana_num = lana;
        ncb.ncb_callname[0] = '*'; ncb.ncb_buffer = (UCHAR*)* ncb.ncb_length = sizeof(ast);
        if (Netbios(&ncb) == NRC_GOODRET) {
            char mac[18];
            sprintf_s(mac, "%02X:%02X:%02X:%02X:%02X:%02X",
                ast.ad.adapter_address[0], ast.ad.adapter_address[1], ast.ad.adapter_address[2],
                ast.ad.adapter_address[3], ast.ad.adapter_address[4], ast.ad.adapter_address[5]);
            macs.push_back(mac);
        }
    }
    return !macs.empty();
}

方法二:COM GUID API (CoCreateGuid) —— 不推薦用於取 MAC

原理:GUID (UUID) 版本 1 由 時間戳 + MAC 位址 生成。CoCreateGuid 回傳的 GUID.Data4[2..7] 理應為 MAC。
致命缺陷:

  • Windows 2000 後預設使用 RFC 4122 版本 4 (隨機) GUID,Data4 為亂數,完全無關 MAC。
  • 虛擬機、Hyper-V、容器環境更無實體 MAC。
  • 僅適合「嘗試取得可能的 MAC」非關鍵邏輯。

代碼 (僅供參考)

GUID guid; CoCreateGuid(&guid);
char mac[18];
sprintf_s(mac, "%02X:%02X:%02X:%02X:%02X:%02X",
    guid.Data4[2], guid.Data4[3], guid.Data4[4],
    guid.Data4[5], guid.Data4[6], guid.Data4[7]);

方法三:SNMP MIB (inetmib1.dll) —— 標準管理方式

優點:符合 RFC 1213 MIB-II 標準,可遠端查詢、支援 IPv6 (IF-MIB)。
缺點:需啟用 SNMP 服務 (現代 Windows 預設關閉);API 複雜、需動態載入 inetmib1.dll。

核心 OID

OID名稱說明
1.3.6.1.2.1.2.1ifNumber介面數量
1.3.6.1.2.1.2.2.1.3ifType介面類型 (6=ethernetCsmacd)
1.3.6.1.2.1.2.2.1.6ifPhysAddressMAC 位址

流程

  1. LoadLibrary("inetmib1.dll") 取得 SnmpExtensionInit/Query 函數指標。
  2. SnmpExtensionInit 初始化。
  3. SnmpExtensionQuery(GETNEXT) 遍歷 ifTable,篩選 ifType==6 且 ifPhysAddress 非全零/非撥號介面 (0x4445535400...)。

綜合比較表

維度NetBIOSGUIDSNMP
可靠度高極低 (隨機)高 (需服務)
相依性NetBIOS 協定OLE32.dllSNMP 服務 + inetmib1.dll
權限需求一般用戶一般用戶一般用戶
多網卡支援完整單一 (隨機)完整
現代適用性良好 (預設開啟)不適用差 (服務預設關閉)
推薦等級★★★★☆☆☆☆☆☆★★☆☆☆

現代最佳實踐:GetAdaptersAddresses (IPHLPAPI)

Windows Vista+ 推薦使用 GetAdaptersAddresses (IPv4/IPv6 通用),無需額外服務,資訊最完整:

#include <iphlpapi.h>
#pragma comment(lib, "iphlpapi.lib")

ULONG bufLen = 0;
GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, nullptr, nullptr, &bufLen);
auto pBuf = std::make_unique<BYTE[]>(bufLen);
PIP_ADAPTER_ADDRESSES pAd = reinterpret_cast<PIP_ADAPTER_ADDRESSES>(pBuf.get());
GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, nullptr, pAd, &bufLen);
for (; pAd; pAd = pAd->Next) {
    if (pAd->PhysicalAddressLength == 6) {
        // pAd->PhysicalAddress 即為 MAC
    }
}

結語

若專案需相容 Windows 2000/XP,**NetBIOS** 是最穩健選擇;Vista 以上**首選 GetAdaptersAddresses**;**嚴禁使用 GUID 取 MAC**。SNMP 僅適用於已部署 SNMP 基礎設施的企業管理軟體。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved