使用VC++创建Win32 Console程序来读取网卡MAC地址的程序

作者在 2009-02-21 21:41:57 发布以下内容

     在实际的应用系统中,我们往往会需要在程序运行时获取当前机器的网卡的MAC地址,以便作为某种标识之用,如控制程序的合法性等。下文就如何用Microsoft Visual C++ 6.0开发这样的程序演示如何实现其要点。

     这里采用的方法是通过Windows 9x/NT/Win2000中内置的NetApi32.DLL的功能来实现的,首先通过发送NCBENUM命令获取网卡的数目和每个网卡的内部编号,然后对每个网卡标号发送NCBASTAT命令获取其MAC地址。注意:这里的网卡是指捆绑了NetBeui协议的通信协议栈,可以在网卡的属性处查看到。请运行VC++,打开一个新的工程,选择创建一个Win32 Console程序,然后按下文输入代码,并请参见其中的注释:

#include "stdafx.h"

#include < windows.h >
#include < wincon.h >
#include < stdlib.h >
#include < stdio.h >
#include < time.h >

// 因为是通过NetAPI来获取网卡信息,所以需要包含其题头文件nb30.h #include < nb30.h >
#include < nb30.h >
#pragma comment(lib,"Netapi32.lib")


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 return 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);
  
  // 对每一张网卡,以其网卡编号为输入编号,获取其MAC地址
  for ( int i=0; i< lana_enum.length; ++i)
   getmac_one( lana_enum.lana[i]);
 }
 return 0;
}

此时,按F7编译、直至通过,按F5运行即可。
这段代码可以直接嵌入相关的应用系统之中,或封装成.DLL或COM控件,以便可以在Visual Basic、Visual Foxpro、Power Builder或Delphi等其他程序中调用

编码 | 阅读 9564 次
文章评论,共3条
vfdff(作者)
2009-02-21 21:45
1
注意Netbios函数使用时的参数<br />
<br />
关键是在调用netbios中使用的参数,我记得有个参数设置的是某个nic&nbsp;&nbsp;&nbsp;(network&nbsp;&nbsp;&nbsp;interface&nbsp;&nbsp;&nbsp;card)&nbsp;&nbsp;&nbsp;的编号,从0开始,但是,在windows中如果有猫安装的话,也是作为一个nic算的,所以如果用ipconfig&nbsp;&nbsp;&nbsp;/all&nbsp;&nbsp;&nbsp;看机器的nic列表会看到多于一个nic,这是就需要自己处理了.<br />
有可能在有猫的机器上,网卡的nic编号是1&nbsp;&nbsp;&nbsp;或者大于1
vfdff(作者)
2009-02-21 22:54
2
建议不要使用Netbios函数,推荐使用IP助手函数。Netbios函数得到的MAC经常是不准确的。它依赖于机器上安装网络协议的顺序。比如先装 IPX协议再装TCP协议,与先装TCP再装IPX所得到的MAC很有可能不一致。这是因为Netbios函数会得到很多的虚拟MAC地址而不是真正的网卡MAC。&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;IPCONFIG就是使用IP助手函数来做的。以下是我的做法请参考:&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;#include&nbsp;&nbsp;&nbsp;&quot;iphlpapi.h&quot;&nbsp;&nbsp;//&nbsp;&nbsp;注意:需要安装SDK才支持此头文件<br />
&nbsp;&nbsp;#pragma&nbsp;&nbsp;&nbsp;comment(lib,&nbsp;&nbsp;&nbsp;&quot;iphlpapi.lib&nbsp;&nbsp;&nbsp;&quot;)&nbsp;&nbsp;<br />
&nbsp;&nbsp;//----------------------------------------------&nbsp;&nbsp;<br />
&nbsp;&nbsp;//功能:获得网卡物理地址&nbsp;&nbsp;<br />
&nbsp;&nbsp;//参数:strMac 返回网卡物理地址&nbsp;&nbsp;<br />
&nbsp;&nbsp;//返回:TRUE 成功&nbsp;&nbsp;<br />
&nbsp;&nbsp;// FALSE 失败&nbsp;&nbsp;<br />
&nbsp;&nbsp;//----------------------------------------------&nbsp;&nbsp;<br />
&nbsp;&nbsp;BOOL&nbsp;&nbsp;&nbsp;CCApp::GetMacAddress(CString&nbsp;&nbsp;&nbsp;&amp;strMac)&nbsp;&nbsp;<br />
&nbsp;&nbsp;{&nbsp;&nbsp;<br />
&nbsp;&nbsp;PIP_ADAPTER_INFO pAdapterInfo;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DWORD AdapterInfoSize;&nbsp;&nbsp;<br />
&nbsp;&nbsp;TCHAR szMac[32]&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;&nbsp;{0};&nbsp;&nbsp;<br />
&nbsp;&nbsp;DWORD Err;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AdapterInfoSize&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;&nbsp;0;&nbsp;&nbsp;<br />
&nbsp;&nbsp;Err&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;&nbsp;GetAdaptersInfo(NULL,&nbsp;&nbsp;&nbsp;&amp;AdapterInfoSize);&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if((Err&nbsp;&nbsp;&nbsp;!=&nbsp;&nbsp;&nbsp;0)&nbsp;&nbsp;&nbsp;&amp;&amp;&nbsp;&nbsp;&nbsp;(Err&nbsp;&nbsp;&nbsp;!=&nbsp;&nbsp;&nbsp;ERROR_BUFFER_OVERFLOW)){&nbsp;&nbsp;<br />
&nbsp;&nbsp;TRACE(&quot;获得网卡信息失败!&quot;);&nbsp;&nbsp;<br />
&nbsp;&nbsp;return&nbsp;&nbsp;&nbsp;FALSE;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //&nbsp;&nbsp;&nbsp;分配网卡信息内存&nbsp;&nbsp;<br />
&nbsp;&nbsp;pAdapterInfo&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;&nbsp;(PIP_ADAPTER_INFO)&nbsp;&nbsp;&nbsp;GlobalAlloc(GPTR,&nbsp;&nbsp;&nbsp;AdapterInfoSize);&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(pAdapterInfo&nbsp;&nbsp;&nbsp;==&nbsp;&nbsp;&nbsp;NULL){&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TRACE(&quot;分配网卡信息内存失败&quot;);&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;&nbsp;&nbsp;FALSE;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(GetAdaptersInfo(pAdapterInfo,&nbsp;&nbsp;&nbsp;&amp;AdapterInfoSize)&nbsp;&nbsp;&nbsp;!=&nbsp;&nbsp;&nbsp;0){&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TRACE(_T(&quot;获得网卡信息失败!\n&quot;));&nbsp;&nbsp;<br />
&nbsp;&nbsp;GlobalFree(pAdapterInfo);&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;&nbsp;&nbsp;FALSE;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;strMac.Format(_T(&quot;%02X%02X%02X%02X%02X%02X&quot;),&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;pAdapterInfo-&gt;Address[0],&nbsp;&nbsp;<br />
&nbsp;&nbsp;pAdapterInfo-&gt;Address[1],&nbsp;&nbsp;<br />
&nbsp;&nbsp;pAdapterInfo-&gt;Address[2],&nbsp;&nbsp;<br />
&nbsp;&nbsp;pAdapterInfo-&gt;Address[3],&nbsp;&nbsp;<br />
&nbsp;&nbsp;pAdapterInfo-&gt;Address[4],&nbsp;&nbsp;<br />
&nbsp;&nbsp;pAdapterInfo-&gt;Address[5]);&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;GlobalFree(pAdapterInfo);&nbsp;&nbsp;<br />
&nbsp;&nbsp;return&nbsp;&nbsp;&nbsp;TRUE;&nbsp;&nbsp;<br />
&nbsp;&nbsp;}
vfdff(作者)
2009-02-22 00:00
3
VS2005支持自带的SDKv2.0,能支持 iphlpapi.h 头文件<br />
VC6 不支持iphlpapi.h 头文件
游客请输入验证码
浏览1942730次