着急!!如何判别机器中有几块网卡?(100分)

  • 主题发起人 主题发起人 DelphiBugs
  • 开始时间 开始时间
D

DelphiBugs

Unregistered / Unconfirmed
GUEST, unregistred user!
如何判别机器中有几块网卡?我已经困扰好几天了。请各位大虾帮个忙.
 
关于具体技术如何实现。
 
因为每块网卡mac地址不同所以找出有几个mac地址就可以了
我曾经问过这样的问题,没有正确答案,现在终于知道如何不通过netbios和guid取mac地址
(从csdn上抄的),把方法告诉大家,省得大家又要拿分出来问。

取得系统中网卡MAC地址的三种方法 ; ; ;
关键字:
NIC MAC CKER ;贴文时间
2001-5-28 22:06:38 ;文章类型:
翻译 ;给贴子投票
投票 ;
; cker ; ;翻译 ;出处: www.borland.com ;
;




取得系统中网卡MAC地址的三种方法


做好的程序员一如做人。多看多想或许他山之石可以攻玉,但永远不要成为代码的奴隶。 CKER
原著:Borland ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;翻译: CKER



--------------------------------------------------------------------------------

;



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, mac_addr))
; ; {
; ; ; cout << "Adapter " << int (AdapterList.lana) <<
; ; ; ; ; ; ; "'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地址。在我的经验里,这个协议很简单。代码也是直勾勾的向前的。基本步骤和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]);
}


;
;
来自:honestman, 时间:2001-5-31 15:51:00, ID:548827
注意换行啊!!!

取得系统中网卡MAC地址的三种方法 ; ; ;
关键字:
NIC MAC CKER ;贴文时间
2001-5-28 22:06:38 ;文章类型:
翻译 ;给贴子投票
投票 ;
; cker ; ;翻译 ;出处: www.borland.com ;
;




取得系统中网卡MAC地址的三种方法


做好的程序员一如做人。多看多想或许他山之石可以攻玉,但永远不要成为代码的奴隶。
CKER
原著:Borland ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;翻译: CKER



------------------------------------------------------------------------------


;



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, mac_addr))
; ; {
; ; ; cout << "Adapter " << int (AdapterList.lana) <<
; ; ; ; ; ; ; "'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地址。在
我的经验里,这个协议很简单。代码也是直勾勾的向前的。基本步骤和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]);
}

;
;
来自:JJams_King, 时间:2001-6-4 11:42:00, ID:553010
好!
;
;
来自:xianjun, 时间:2001-6-4 14:27:00, ID:553228
第二种办法应该不能用吧? 每次运行结果都不同
第三种办法哪位高手帮忙翻译成DELPHI下的代码?
我用第一种办法写了一下, 不知是否正确, 大家帮忙看看:
FORM:

object Form1: TForm1
; Left = 223
; Top = 107
; Width = 335
; Height = 409
; Caption = 'Form1'
; Color = clBtnFace
; Font.Charset = DEFAULT_CHARSET
; Font.Color = clWindowText
; Font.Height = -12
; Font.Name = '宋体'
; Font.Style = []
; OldCreateOrder = False
; PixelsPerInch = 96
; TextHeight = 12
; object Button1: TButton
; ; Left = 240
; ; Top = 352
; ; Width = 75
; ; Height = 25
; ; Caption = 'Button1'
; ; TabOrder = 0
; ; OnClick = Button1Click
; end
; object Memo1: TMemo
; ; Left = 8
; ; Top = 8
; ; Width = 309
; ; Height = 333
; ; TabOrder = 1
; end
end

PAS:

unit Main;

interface

uses
; Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
; StdCtrls;

type
; TForm1 = class(TForm)
; ; Button1: TButton;
; ; Memo1: TMemo;
; ; procedure Button1Click(Sender: TObject);
; private
; ; { Private declarations }
; public
; ; { Public declarations }
; end;

var
; Form1: TForm1;

implementation

{$R *.DFM}
uses
; NB30;

function GetAdapterInfo(Adapter_num: Char; var AMac_Addr: string): Boolean;
type
; TStat = record
; ; Adapt: TAdapterStatus;
; ; Name_Buffer: TNameBuffer;
; end;
var
; P: PNCB;
; Adapter: TStat;
; Temp: Char;
begin
; New(P);
; try
; // 重置网卡,以便我们可以查询
; ; FillChar(P^, SizeOf(TNcb), #0);
; ; P^.ncb_command := Chr(NCBRESET);
; ; P^.ncb_lana_num := adapter_num;
; ; Temp := Netbios(P);
; ; if Temp <> Chr(NRC_GOODRET) then
; ; begin
; ; ; AMac_Addr := 'bad (NCBRESET): ' + P^.Ncb_retcode;
; ; ; Result := False;
; ; ; Exit;
; ; end;
; ; FillChar(P^, SizeOf(TNcb), #0);
; ; P^.ncb_command := Chr(NCBASTAT);
; ; P^.ncb_lana_num := Adapter_num;
; ; P^.ncb_callname := '*';
; ; FillChar(Adapter, SizeOf(TStat), #0);
; ; P^.ncb_buffer := @Adapter;
; ; P^.ncb_length := Sizeof(Adapter);
; // 取得网卡的信息,并且如果网卡正常工作的话,返回标准的冒号分隔格式。
; ; Temp := Netbios(P);
; ; if Temp = #0 then
; ; begin
; ; ; AMac_Addr := Format('%0.2x:%0.2x:%0.2x:%0.2x:%0.2x:%0.2x', [Ord(Adapter.adapt.adapter_address[0]),
; ; ; ; Ord(Adapter.adapt.adapter_address[1]), Ord(Adapter.adapt.adapter_address[2]),
; ; ; ; ; Ord(Adapter.adapt.adapter_address[3]), Ord(Adapter.adapt.adapter_address[4]),
; ; ; ; ; Ord(Adapter.adapt.adapter_address[5])]);
; ; end;
; finally
; ; Dispose(P);
; end;
; Result := True;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
; AdapterList: TLanaEnum;
; Ncb: PNcb;
; I: Integer;
; Mac_addr: string;
begin
; New(Ncb);
; try
; // 取得网卡列表
; ; FillChar(Ncb^, SizeOf(TNcb), #0);
; ; FillChar(AdapterList, Sizeof(AdapterList), #0);
; ; Ncb.ncb_command := Chr(NCBENUM);
; ; Ncb.ncb_buffer := @AdapterList;
; ; Ncb.ncb_length := Sizeof(AdapterList);
; ; Netbios(Ncb);
; ; for I := 0 to Ord(AdapterList.Length) - 1 do
; ; begin
; ; ; if GetAdapterInfo(AdapterList.lana, Mac_addr) then
; ; ; ; Memo1.Lines.Add(Format('Adapter %d''s MAC is %s', [Ord(AdapterList.lana), Mac_addr]))
; ; ; else
; ; ; begin
; ; ; ; Memo1.Lines.Add('Failed to get MAC address! Do you have the NetBIOS protocol installed?');
; ; ; ; Break;
; ; ; end;
; ; end;
; finally
; ; Dispose(Ncb);
; end;
end;

end.

;
;
来自:honghs, 时间:2001-6-4 14:37:00, ID:553241
xianjun, 应该是第二种方法在nt和2k下不能用,不信你换到98下看看,每次结果都是一样的
至于第一种方法,它的缺点是你必须安装netbios协议,而nt和2k缺省是不装这个协议的。
第三种方法应该是nt和2k下的标准用法,你找人翻译去吧,我当初看msdn看得头都大了才
大概知道用snmp可以取,却不知如何取。
;
;
来自:江小鱼儿, 时间:2001-6-22 11:17:00, ID:577469
什么是MAC,NIC,CKER ;.
;
;
来自:honghs, 时间:2001-8-20 7:51:00, ID:601932
接受答案了.
;
;
 
lyywy兄,多谢你的热心。现在还有一点不明,关于拨号适配器也有MAC地址,
但其不是“真正“的网卡,我现在想要知道的是一台机器中真正的网卡数量,请问如何实现?
您的热心让我很感动,如果您帮我解决该问题,小弟一定全力感谢!!此处先送上20分。
 
后退
顶部