| 導購 | 订阅 | 在线投稿
分享
 
 
 

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

來源:互聯網  2008-06-01 02:08:11  評論

做好的程序員一如做人。多看多想或許他山之石可以攻玉,但永遠不要成爲代碼的奴隸。 CKER

原著:Borland

Translated by CKER

第一種方法使用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

&nbs

做好的程序員一如做人。多看多想或許他山之石可以攻玉,但永遠不要成爲代碼的奴隸。 CKER 原著:Borland Translated by CKER 第一種方法使用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 &nbs
󰈣󰈤
王朝萬家燈火計劃
期待原創作者加盟
 
 
 
>>返回首頁<<
 
 
 
 
 熱帖排行
 
 
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有