1. gzyueqian
      18529173453
      首頁 > 新聞中心 > > 正文

      取得系統中網卡MAC地址的三種方法

      更新時間: 2007-05-10 10:13:40來源: 粵嵌教育瀏覽量:1920


        種方法使用Microsoft的Netbios API

         這是一套通過Winsock提供底層網絡支持的命令。使用Netbios的缺點是您必須在系統中安裝了Netbios服務(如果您在windows網絡中啟用了文件共享的話,這就不是問題了)。除此此外,這種方法又快又準確。

        Netbios API只包括了一個函數,就叫做Netbios。這個函數使用網絡控制塊(network control block)結構作為參數,這個結構告訴函數要做什么。結構的定義如下:
      typedef struct _NCB {
      UCHAR ncb_command;
      UCHAR ncb_retcode;
      UCHAR ncb_lsn;
      UCHAR ncb_num;
      PUCHAR ncb_buffer;
      WORD ncb_length;
      UCHAR ncb_callname[NCBNAMSZ];
      UCHAR ncb_name[NCBNAMSZ];
      UCHAR ncb_rto;
      UCHAR ncb_sto;
      void (CALLBACK *ncb_post) (struct _NCB *);
      UCHAR ncb_lana_num;
      UCHAR ncb_cmd_cplt;
      #ifdef _WIN64
      UCHAR ncb_reserve[18];
      #else
      UCHAR ncb_reserve[10];
      #endif
      HANDLE ncb_event;
      } NCB, *PNCB;

        重點在于ncb_command 成員。這個成員告訴Netbios該作什么。我們使用三個命令來探測MAC地址。他們在MSDN的定義如下:
      命令描述:
        NCBENUM Windows NT/2000: 列舉系統中網卡的數量。使用此命令后,ncb_buffer成員指向由LANA_ENUM結構填充的緩沖區。
      NCBENUM 不是標準的 NetBIOS 3.0 命令。

        NCBRESET 重置網卡。網卡在接受新的NCB命令之前必須重置。
        NCBASTAT 接受本地或遠程接口卡的狀態。使用此命令后,ncb_buffer成員指向由ADAPTER_STATUS結構填充的緩沖區,隨后是NAME_BUFFER結構的數組。

      下面就是取得您系統MAC地址的步驟:
      1》列舉所有的接口卡。
      2》重置每塊卡以取得它的正確信息。
      3》查詢接口卡,取得MAC地址并生成標準的冒號分隔格式。

      下面就是實例源程序。
      netbios.cpp

      #include <windows.h>
      #include <stdlib.h>
      #include <stdio.h>
      #include <iostream>
      #include <string>

      using namespace std;
      #define bzero(thing,sz) memset(thing,0,sz)

      bool GetAdapterInfo(int adapter_num, string &mac_addr)
      {
      // 重置網卡,以便我們可以查詢
      NCB Ncb;
      memset(&Ncb, 0, sizeof(Ncb));
      Ncb.ncb_command = NCBRESET;
      Ncb.ncb_lana_num = adapter_num;
      if (Netbios(&Ncb) != NRC_GOODRET) {
      mac_addr = "bad (NCBRESET): ";
      mac_addr += string(Ncb.ncb_retcode);
      return false;
      }

      // 準備取得接口卡的狀態塊
      bzero(&Ncb,sizeof(Ncb);
      Ncb.ncb_command = NCBASTAT;
      Ncb.ncb_lana_num = adapter_num;
      strcpy((char *) Ncb.ncb_callname, "*");
      struct ASTAT
      {
      ADAPTER_STATUS adapt;
      NAME_BUFFER NameBuff[30];
      } Adapter;
      bzero(&Adapter,sizeof(Adapter));
      Ncb.ncb_buffer = (unsigned char *)&Adapter;
      Ncb.ncb_length = sizeof(Adapter);

      // 取得網卡的信息,并且如果網卡正常工作的話,返回標準的冒號分隔格式。
      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]));
      mac_addr = acMAC;
      return true;
      }
      else
      {
      mac_addr = "bad (NCBASTAT): ";
      mac_addr += string(Ncb.ncb_retcode);
      return false;
      }
      }

      int main()
      {
      // 取得網卡列表
      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);

      // 取得本地以太網卡的地址
      string mac_addr;
      for (int i = 0; i < AdapterList.length - 1; ++i)
      {
      if (GetAdapterInfo(AdapterList.lana[i], mac_addr))
      {
      cout << "Adapter " << int (AdapterList.lana[i]) <<
      "'s MAC is " << mac_addr << endl;
      }
      else
      {
      cerr << "Failed to get MAC address! Do you" << endl;
      cerr << "have the NetBIOS protocol installed?" << endl;
      break;
      }
      }

      return 0;
      }


      file://---------------------------------------------------------------------------


        第二種方法-使用COM GUID API


        這種方法使用COM API創建一個GUID(全局標識符)并從那里繼承MAC地址。GUID通常用來標識COM組件以及系統中的其他對象。它們是由MAC地址(結合其他東西)計算得來的,表面上MAC地址就包含在其中。我說表面上是因為事實上并沒有包含。
        我提供這種方法更多的是為了作為反面教材。您也許用這種方法能夠得到MAC地址,但有時候您只會得到隨機的十六進制數值。
      下面的例子十分簡單,無需多講。我們使用CoCreateGuid創建GUID,并將六個字節放入字符串中。它們可能是MAC地址,但并不是必然的。

      uuid.cpp
      #include <windows.h>
      #include <iostream>
      #include <conio.h>

      using namespace std;

      int main()
      {
      cout << "MAC address is: ";

      // 向COM要求一個UUID。如果機器中有以太網卡,
      // UUID的六個字節(Data4的2-7字節)應該是本地以太網卡的MAC地址。
      GUID uuid;
      CoCreateGuid(&uuid);
      // Spit the address out
      char mac_addr[18];
      sprintf(mac_addr,"%02X:%02X:%02X:%02X:%02X:%02X",
      uuid.Data4[2],uuid.Data4[3],uuid.Data4[4],
      uuid.Data4[5],uuid.Data4[6],uuid.Data4[7]);
      cout << mac_addr << endl;
      getch();
      return 0;
      }


        第三種方法- 使用SNMP擴展API

        我要討論的第三種方法是使用Windows的SNMP(簡單網絡管理協議)擴展來取得MAC地址。在我的經驗里,這個協議很簡單。代碼也是直勾勾的向前的?;静襟E和Netbios相同:
      1》取得網卡列表
      2》查詢每塊卡的類型和MAC地址
      3》保存當前網卡
      筆者對SNMP了解不多,但如我剛剛所言,代碼十分清楚。

      snmp.cpp
      #include <snmp.h>
      #include <conio.h>
      #include <stdio.h>

      typedef bool(WINAPI * pSnmpExtensionInit) (
      IN DWORD dwTimeZeroReference,
      OUT HANDLE * hPollForTrapEvent,
      OUT AsnObjectIdentifier * supportedView);

      typedef bool(WINAPI * pSnmpExtensionTrap) (
      OUT AsnObjectIdentifier * enterprise,
      OUT AsnInteger * genericTrap,
      OUT AsnInteger * specificTrap,
      OUT AsnTimeticks * timeStamp,
      OUT RFC1157VarBindList * variableBindings);

      typedef bool(WINAPI * pSnmpExtensionQuery) (
      IN BYTE requestType,
      IN OUT RFC1157VarBindList * variableBindings,
      OUT AsnInteger * errorStatus,
      OUT AsnInteger * errorIndex);

      typedef bool(WINAPI * pSnmpExtensionInitEx) (
      OUT AsnObjectIdentifier * supportedView);

      void main()
      {
      HINSTANCE m_hInst;
      pSnmpExtensionInit m_Init;
      pSnmpExtensionInitEx m_InitEx;
      pSnmpExtensionQuery m_Query;
      pSnmpExtensionTrap m_Trap;
      HANDLE PollForTrapEvent;
      AsnObjectIdentifier SupportedView;
      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};
      RFC1157VarBindList varBindList;
      RFC1157VarBind varBind[2];
      AsnInteger errorStatus;
      AsnInteger errorIndex;
      AsnObjectIdentifier MIB_NULL = {0, 0};
      int ret;
      int dtmp;
      int i = 0, j = 0;
      bool found = false;
      char TempEthernet[13];
      m_Init = NULL;
      m_InitEx = NULL;
      m_Query = NULL;
      m_Trap = NULL;

      /* 載入SNMP DLL并取得實例句柄 */
      m_hInst = LoadLibrary("inetmib1.dll");
      if (m_hInst < (HINSTANCE) HINSTANCE_ERROR)
      {
      m_hInst = NULL;
      return;
      }
      m_Init =
      (pSnmpExtensionInit) GetProcAddress(m_hInst, "SnmpExtensionInit");
      m_InitEx =
      (pSnmpExtensionInitEx) GetProcAddress(m_hInst,
      "SnmpExtensionInitEx");
      m_Query =
      (pSnmpExtensionQuery) GetProcAddress(m_hInst,
      "SnmpExtensionQuery");
      m_Trap =
      (pSnmpExtensionTrap) GetProcAddress(m_hInst, "SnmpExtensionTrap");
      m_Init(GetTickCount(), &PollForTrapEvent, &SupportedView);

      /* 初始化用來接收m_Query查詢結果的變量列表 */
      varBindList.list = varBind;
      varBind[0].name = MIB_NULL;
      varBind[1].name = MIB_NULL;

      /* 在OID中拷貝并查找接口表中的入口數量 */
      varBindList.len = 1; /* Only retrieving one item */
      SNMP_oidcpy(&varBind[0].name, &MIB_ifEntryNum);
      ret =
      m_Query(ASN_RFC1157_GETNEXTREQUEST, &varBindList, &errorStatus,
      &errorIndex);
      printf("# of adapters in this system : %in",
      varBind[0].value.asnValue.number);
      varBindList.len = 2;

      /* 拷貝OID的ifType-接口類型 */
      SNMP_oidcpy(&varBind[0].name, &MIB_ifEntryType);

      /* 拷貝OID的ifPhysAddress-物理地址 */
      SNMP_oidcpy(&varBind[1].name, &MIB_ifMACEntAddr);

      do
      {

      /* 提交查詢,結果將載入 varBindList。
      可以預料這個循環調用的次數和系統中的接口卡數量相等 */
      ret =
      m_Query(ASN_RFC1157_GETNEXTREQUEST, &varBindList, &errorStatus,
      &errorIndex);
      if (!ret)
      ret = 1;
      else
      /* 確認正確的返回類型 */
      ret =
      SNMP_oidncmp(&varBind[0].name, &MIB_ifEntryType,
      MIB_ifEntryType.idLength); if (!ret) {
      j++;
      dtmp = varBind[0].value.asnValue.number;
      printf("Interface #%i type : %in", j, dtmp);

      /* Type 6 describes ethernet interfaces */
      if (dtmp == 6)
      {

      /* 確認我們已經在此取得地址 */
      ret =
      SNMP_oidncmp(&varBind[1].name, &MIB_ifMACEntAddr,
      MIB_ifMACEntAddr.idLength);
      if ((!ret) && (varBind[1].value.asnValue.address.stream != NULL))
      {
      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))
      {
      /* 忽略所有的撥號網絡接口卡 */
      printf("Interface #%i is a DUN adaptern", j);
      continue;
      }
      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))
      {
      /* 忽略由其他的網絡接口卡返回的NULL地址 */
      printf("Interface #%i is a NULL addressn", j);
      continue;
      }
      sprintf(TempEthernet, "%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]);
      printf("MAC Address of interface #%i: %sn", j,
      TempEthernet);}
      }
      }
      } while (!ret); /* 發生錯誤終止。 */
      getch();

      FreeLibrary(m_hInst);
      /* 解除綁定 */
      SNMP_FreeVarBind(&varBind[0]);
      SNMP_FreeVarBind(&varBind[1]);
      }

      免費預約試聽課

      亚洲另类欧美综合久久图片区_亚洲中文字幕日产无码2020_欧美日本一区二区三区桃色视频_亚洲AⅤ天堂一区二区三区

      
      

      1. 视频列表中文字幕欧美国产 | 尤物yw193在线视频 | 一本大道AV伊人久久综合 | 亚洲字幕一级二级 | 线观看国产精品视频 | 污污精品91网站在线观看 |