在实际应用程序中,往往会需要在程序运行时获取当前机器网卡的MAC地址,以便作为某种标识之用。如何用VC实现这个功能呢?

2010-12-24 21:42:58

4 Answers

通用的方法是通过Windows 9x/NT/Win2000 中内置的NetApi32.DLL 的功能来实现的。首先通过发送NCBENUM 命令,获取网卡的数目和每张网卡的内部编号,然后对每个网卡标号发送NCBASTAT 命令获取其MAC 地址。注意:这里的网卡是指捆绑了NetBEIU 协议的通信协议栈,可以在网卡的属性处查看到。

示例代码:

// Mac-Reader.cpp : Defines the entry point for the console application. #include "stdafx.h" #include <windows.h> #include <wincon.h> #include <nb30.h> // 因为是通过NetAPI来获取网卡信息,所以需要包含其题头文件nb30.h #include <stdlib.h> #include <stdio.h> #include <time.h> typedef struct _ASTAT_ { ADAPTER_STATUS adapt; NAME_BUFFER NameBuff [30]; }ASTAT, * PASTAT; ASTAT Adapter; // 定义一个存放返回网卡信息的变量 // 输入参数:lana_num为网卡编号,一般地,从0开始,但在Windows 2000中并不一定是连续分配的 void getmac_one (int lana_num) { NCB ncb; UCHAR uRetCode; memset( &ncb, 0, sizeof(ncb) ); ncb.ncb_command = NCBRESET; ncb.ncb_lana_num = lana_num; // 指定网卡号 // 首先对选定的网卡发送一个NCBRESET命令,以便进行初始化 uRetCode = Netbios( &ncb ); printf( "The NCBRESET return code is:0x%x /n", uRetCode ); memset( &ncb, 0, sizeof(ncb) ); ncb.ncb_command = NCBASTAT; ncb.ncb_lana_num = lana_num; // 指定网卡号 strcpy( (char *)ncb.ncb_callname,"* " ); ncb.ncb_buffer = (unsigned char *) &Adapter; // 指定返回的信息存放的变量 ncb.ncb_length = sizeof(Adapter); // 接着,可以发送NCBASTAT命令以获取网卡的信息 uRetCode = Netbios( &ncb ); printf( "The NCBASTAT eturn code is: 0x%x /n", uRetCode ); if ( uRetCode == 0 ) { // 把网卡MAC地址格式化成常用的16进制形式,如0010-A4E4-5802 printf( "The Ethernet Number[%d] is: %02X-%02X-%02X-%02X-%02X-%02X/n", lana_num, Adapter.adapt.adapter_address[0], Adapter.adapt.adapter_address[1], Adapter.adapt.adapter_address[2], Adapter.adapt.adapter_address[3], Adapter.adapt.adapter_address[4], Adapter.adapt.adapter_address[5] ); } } int main(int argc, char* argv[]) { NCB ncb; UCHAR uRetCode; LANA_ENUM lana_enum; memset( &ncb, 0, sizeof(ncb) ); ncb.ncb_command = NCBENUM; ncb.ncb_buffer = (unsigned char *) &lana_enum; ncb.ncb_length = sizeof(lana_enum); // 向网卡发送NCBENUM命令,以获取当前机器的网卡信息,如有多少个网卡、每张网卡的编号等 uRetCode = Netbios( &ncb ); printf( "The NCBENUM return code is:0x%x /n", uRetCode ); if ( uRetCode == 0 ) { printf( "Ethernet Count is : %d/n/n", lana_enum.length); getmac_one( lana_enum.lana[0]);//对第一个网卡 //如果你有多张网卡 /* for ( int i=0; i< lana_enum.length; ++i) // getmac_one( lana_enum.lana[i]); */ } return 0; }

2010-12-25 00:09:49

之前项目中用到的代码:
// 网卡 MAC 地址,注意: MAC 地址是可以在注册表中修改的
通过API直接获取
 

BOOL GetMacAddress(std::wstring &strMacAddr) { PIP_ADAPTER_INFO pAdapterInfo; DWORD AdapterInfoSize; DWORD Err; AdapterInfoSize = 0; Err = GetAdaptersInfo(NULL, &AdapterInfoSize); if((Err != 0) && (Err != ERROR_BUFFER_OVERFLOW)) { ATLTRACE("获得网卡信息失败!"); return FALSE; } // 分配网卡信息内存 pAdapterInfo = (PIP_ADAPTER_INFO) GlobalAlloc(GPTR, AdapterInfoSize); if(pAdapterInfo == NULL) { ATLTRACE("分配网卡信息内存失败"); return FALSE; } if(GetAdaptersInfo(pAdapterInfo, &AdapterInfoSize) != 0) { ATLTRACE(_T("获得网卡信息失败!\n")); GlobalFree(pAdapterInfo); return FALSE; } wchar_t str[256]={0}; wsprintfW(str,L"%02X%02X%02X%02X%02X%02X", pAdapterInfo->Address[0], pAdapterInfo->Address[1], pAdapterInfo->Address[2], pAdapterInfo->Address[3], pAdapterInfo->Address[4], pAdapterInfo->Address[5]); GlobalFree(pAdapterInfo); strMacAddr = str; return TRUE; }

2010-12-25 00:50:13

 网卡的MAC地址是可以伪造的,但是魔高一尺,道高一丈,还是有办法获取网卡的真实MAC地址的。基本思想是DeviceIoControl函数和网卡驱动直接打交道,从驱动中获取真实的MAC地址。具体的实现可参见:通过WDK获取网卡原生MAC地址和当前MAC地址

2010-12-25 03:15:12

网上找到的一份代码,LZ可以参考一下

// Mac-Reader.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include 
#include 
#include 
// 因为是通过NetAPI来获取网卡信息,所以需要包含其题头文件nb30.h  
#include 
#include 
#include 

typedef struct _ASTAT_
{
    ADAPTER_STATUS adapt;
    NAME_BUFFER    NameBuff [30];
}ASTAT, * PASTAT;

ASTAT Adapter;    

// 定义一个存放返回网卡信息的变量 
// 输入参数:lana_num为网卡编号,一般地,从0开始,但在Windows 2000中并不一定是连续分配的 

void getmac_one (int lana_num)
{
    NCB ncb;
    UCHAR uRetCode;

    memset( &ncb, 0, sizeof(ncb) );
    ncb.ncb_command = NCBRESET;
    ncb.ncb_lana_num = lana_num;   
    // 指定网卡号

    // 首先对选定的网卡发送一个NCBRESET命令,以便进行初始化 
    uRetCode = Netbios( &ncb );
    printf( "The NCBRESET return code is:0x%x /n", uRetCode );

    memset( &ncb, 0, sizeof(ncb) );
    ncb.ncb_command = NCBASTAT;
    ncb.ncb_lana_num = lana_num;     // 指定网卡号

    strcpy( (char *)ncb.ncb_callname,"*               " );
    ncb.ncb_buffer = (unsigned char *) &Adapter;

    // 指定返回的信息存放的变量 
    ncb.ncb_length = sizeof(Adapter);

    // 接着,可以发送NCBASTAT命令以获取网卡的信息 
    uRetCode = Netbios( &ncb );
    printf( "The NCBASTAT eturn code is: 0x%x /n", uRetCode );
    if ( uRetCode == 0 )
    {

        // 把网卡MAC地址格式化成常用的16进制形式,如0010-A4E4-5802 
        printf( "The Ethernet Number[%d] is: %02X-%02X-%02X-%02X-%02X-%02X/n",
            lana_num,
            Adapter.adapt.adapter_address[0],
            Adapter.adapt.adapter_address[1],
            Adapter.adapt.adapter_address[2],
            Adapter.adapt.adapter_address[3],
            Adapter.adapt.adapter_address[4],
            Adapter.adapt.adapter_address[5] );
    }
}

int main(int argc, char* argv[]) 
{
    NCB ncb;
    UCHAR uRetCode;
    LANA_ENUM lana_enum;

    memset( &ncb, 0, sizeof(ncb) );
    ncb.ncb_command = NCBENUM;

    ncb.ncb_buffer = (unsigned char *) &lana_enum;
    ncb.ncb_length = sizeof(lana_enum);

    // 向网卡发送NCBENUM命令,以获取当前机器的网卡信息,如有多少个网卡、每张网卡的编号等 
    uRetCode = Netbios( &ncb );
    printf( "The NCBENUM return code is:0x%x /n", uRetCode );
    if ( uRetCode == 0 )
    {
        printf( "Ethernet Count is : %d/n/n", lana_enum.length);
        
        getmac_one( lana_enum.lana[0]);//对第一个网卡
        //如果你有多张网卡
        /*
            for ( int i=0; i< lana_enum.length; ++i) // getmac_one( lana_enum.lana[i]); */ } return 0; }
2010-12-25 03:57:56
您不能回答该问题或者回答已经关闭!

相关文章推荐

  • C#中using指令的几种用法

    using + 命名空间名字,这样可以在程序中直接用命令空间中的类型,而不必指定类型的详细命名空间,类似于Java的import,这个功能也是最常用的,几乎每个cs的程序都会用到

  • C#实例解析适配器设计模式

    将一个类的接口变成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够一起工作

  • C#开发高性能Log Help类设计开发

    项目中要在操作数据库的异常处理中加入写Log日志,对于商业上有要求,写log时对其它操作尽可能影响小,不能因为加入log导致耗时太多

  • 使用托管C++粘合C#和C++代码(二)

    本文实现一下C++代码调用C#代码的过程。我构造一个简单并且直观的例子:通过C++ UI 触发C# UI.

  • Async和Await使异步编程更简单

    C#5.0中async和await两个关键字,这两个关键字简化了异步编程,之所以简化了,还是因为编译器给我们做了更多的工作

  • C#开发中的反射机制

    反射的定义:审查元数据并收集关于它的类型信息的能力。元数据(编译以后的最基本数据单元)就是一大堆的表,当编译程序集或者模块时,编译器会创建一个类定义表,一个字段定义表,和一个方法定义表等

  • C#运行时相互关系

    C#运行时相互关系,包括运行时类型、对象、线程栈和托管堆之间的相互关系,静态方法、实例方法和虚方法的区别等等

  • C#协变和逆变

    “协变”是指能够使用与原始指定的派生类型相比,派生程度更大的类型,“逆变”则是指能够使用派生程度更小的类型

  • C#基础概念之延迟加载

    延迟加载(lazy load)是Hibernate3关联关系对象默认的加载方式,延迟加载机制是为了避免一些无谓的性能开销而提出来的,所谓延迟加载就是当在真正需要数据的时候,才真正执行数据加载操作

  • 使用托管C++粘合C#和C++代码(一)

    C#在xml读写,数据库操纵,界面构造等很多方面性能卓越;C++的效率高,是底层开发的必备武器

  • C#中的索引器的简单理解和用法

    C#中的类成员可以是任意类型,包括数组和集合。当一个类包含了数组和集合成员时,索引器将大大简化对数组或集合成员的存取操作

  • 深入C# 序列化(Serialize)、反序列化(Deserialize)

    C#中的序列化和反序列化,序列化是.NET运行时环境用来支持用户定义类型的流化的机制