以下代码枚举所有LANA号码,执行复位(NCBREST)和适配器状态(NCBASTAT)。
#include <windows.h>
#include <wincon.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
typedef struct _ASTAT_
{
ADAPTER_STATUS adapt;
NAME_BUFFER NameBuff [30];
}ASTAT, * PASTAT;
ASTAT Adapter;
void main (void)
{
NCB Ncb;
UCHAR uRetCode;
char NetName[50];
LANA_ENUM lenum;
int i;
memset( &Ncb, 0, sizeof(Ncb) );
Ncb.ncb_command = NCBENUM;
Ncb.ncb_buffer = (UCHAR *)&lenum;
Ncb.ncb_length = sizeof(lenum);
uRetCode = Netbios( &Ncb );
printf( "The NCBENUM return code is: 0x%x \n", uRetCode );
for(i=0; i < lenum.length ;i++)
{
memset( &Ncb, 0, sizeof(Ncb) );
Ncb.ncb_command = NCBRESET;
Ncb.ncb_lana_num = lenum.lana[i];
uRetCode = Netbios( &Ncb );
printf( "The NCBRESET on LANA %d return code is: 0x%x \n",
lenum.lana[i], uRetCode );
memset( &Ncb, 0, sizeof (Ncb) );
Ncb.ncb_command = NCBASTAT;
Ncb.ncb_lana_num = lenum.lana[i];
strcpy( Ncb.ncb_callname, "* " );
Ncb.ncb_buffer = (char *) &Adapter;
Ncb.ncb_length = sizeof(Adapter);
uRetCode = Netbios( &Ncb );
printf( "The NCBASTAT on LANA %d return code is: 0x%x \n",
lenum.lana[i], uRetCode );
if ( uRetCode == 0 )
{
printf( "The Ethernet Number on LANA %d is:
%02x%02x%02x%02x%02x%02x\n",
lenum.lana[i],
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] );
}
}
}
众所周知,一个网卡对应唯一MAC地址,对一些应用程序来说,获取网卡MAC地址有时是必要的,使用VC提供的netbios网络编程接口可以方便获取网卡MAC地址。
netbios中所用的函数声明、常数等等均是在头文件nb30.h内定义的,若想使用netbios,须连接的库是netapi32.lib。调用netbios函数时,使用uRetCode = netbios(&ncb)语句,其入口参数&ncb为指向一网络控制块(NCB)的指针。在该NCB结构中,包含了为执行一个netbios命令相应需预先准备(在调用前)或命令执行结果(在调用后)的全部信息,在调用netbios函数前要先预置好该NCB结构中的一些有关字段;返回码uRetCode正常时应为0,返回的具体结果会包含在NCB结构的一些字段中。
NCB结构的定义如下:
typedef struct _NCB{
UCHAR ncb_command; //用于指定要执行的NetBIOS命令, 一些常见的NetBIOS命令如附表所示
UCHAR ncb_retcode; //用于指定操作的返回代码,若返回值为0,就表示操作成功
UCHAR ncb_lsn; //对应一个本地会话编号,成功的执行了一次NCBCALL或NCBLISTEN命令后, //函数会返回一个会话编号
UCHAR ncb_num; //用于知道本地名字的编号,伴随NCBADDNAME或NCBADDGRNAME命令的 //每一次调用,都会返回一个新的编号
PUCHAR ncb_buffer; //指向数据缓冲区,发送时该缓冲区包含了要送出去的实际数据,接收时的接收
//数据则为从NetBIOS函数返回的数据;对其他命令来说,如NCBENUM,缓冲 //区便是预定义的结构LANA_ENUM
WORD ncb_length; //指定缓冲区的长度,以字节数为单位,接收时NetBios会将该值设为收到的字节
//数,若指定的缓冲区不够大,NetBIOS就会返回NRC_BUFLEND错误
UCHAR ncb_callname[NCBNAMSZ]; //用于指定远程应用的名字
UCHAR ncb_name[NCBNAMSZ]; //用于指定应用程序已知的名字
UCHAR ncb_rto; //规定接收操作时的会话超时(以0.5秒为单位)
UCHAR ncb_sto; //规定发送操作时的会话超时(以0.5秒为单位)
viod (CALLBACK *ncb_post) (struct _NCB *); //异步命令完成后,调用的后处理程序地址
UCHAR ncb_lana_num; //指定LAN Adapter编号
UCHAR ncb_cmd_cplt; //用于指定操作的返回代码,异步操作进行期间,Netbios会将这个值设为
//NRC_PENDING
UCHAR ncb_reserve[10]; //保留,必须为0
HANDLE ncb_event; //事件对象的句柄,netbios函数返回非0值时会发信号给事件
}NCB, *PNCB;
nb30.h中还定义了另外一个很重要的结构LANA_ENUM,当主机中有两块以上网卡时,使用NCB命令NCBENUM后(该命令只能在Windows NT/2000/XP中使用),该结构中会含有返回的网卡数目及其索引,该结构的定义如下:
typedef struct LANA_ENUM {
UCHAR length;
UCHAR lana [MAX_LANA];
} LANA_ENUM, *PLANA_ENUM;
其中:lana [MAX_LANA]定义了一个存放所有网卡信息的数组,length表示该数组的长度,即为本机所带网卡的个数。此外,我们还要定义一个描述网卡的结构ASTAT,其中使用了结构ADAPTER_STATUS(也由
nb30.h定义):
typedef struct {
ADAPTER_STATUS adapt;
NAME_BUFFER NameBuff[30];
} ASTAT;
其中的ADAPTER_STATUS结构为
typedef struct _ADAPTER_STATUS {
UCHAR adapter_address[6]; //网卡MAC地址
UCHAR rev_major;
UCHAR reserved0;
UCHAR adapter_type;
UCHAR rev_minor;
WORD duration;
WORD frmr_recv;
WORD frmr_xmit;
WORD iframe_recv_err;
WORD xmit_aborts;
DWORD xmit_success;
DWORD recv_success;
WORD iframe_xmit_err;
WORD recv_buff_unavail;
WORD t1_timeouts;
WORD ti_timeouts;
DWORD eserved1;
WORD free_ncbs;
WORD max_cfg_ncbs;
WORD max_ncbs;
WORD xmit_buf_unavail;
WORD max_dgram_size;
WORD pending_sess;
WORD max_cfg_sess;
WORD max_sess;
WORD max_sess_pkt_size;
WORD name_count;
} ADAPTER_STATUS, *PADAPTER_STATUS;
在调用netbios NCBASTAT命令前,我们可将指向ADAPTER_STATUS结构的指针值赋给缓冲区指针ncb.ncb_buffer,
ASTAT Adapter;
ncb.ncb_buffer = (unsigned char *) &Adapter; //两个指针指向同一个地方
ncb.ncb_length = sizeof(Adapter); // 设置ncb_buffer缓冲区长度
这样在执行NCBASTAT命令后,由于ncb.ncb_buffer指针所指的缓冲区中为命令执行后网卡返回的统计结果(其中包含MAC网卡地址),我们使用与其同一地址的ADAPTER_STATUS结构的adapter_address[6]字段便可取出网卡地址。
几点说明:
1.由于ncb_command字段用于指定要执行的netbios命令,所以总是在执行一个netbios命令之前设置该
ncb_command字段。例如:
(1)我们要获取当前计算机有多少个网卡,则可用以下一段代码来实现:
NCB ncb;
UCHAR uRetCode = Netbios(&ncb);
int num; //标识网卡个数
num = lana_enum.length;
(2)对网卡进行初始化可用以下代码实现:
memset(&ncb, 0, sizeof(ncb));
ncb.ncb_command = NCBRESET;
ncb.ncb_lana_num = 0;
uRetCode = Netbios(&ncb );
(3)查询网卡包括MAC地址等在内的信息可用以下代码实现:
memset(&ncb, 0, sizeof(ncb));
ncb.ncb_command = NCBASTAT;
ncb.ncb_lana_num = 0;
sNetBiosName ="*";
FillMemory(ncb.ncb_callname, NCBNAMSZ - 1, 0x20);
strcpy((char *)ncb.ncb_callname, (LPCTSTR) sNetBiosName);
ncb.ncb_callname[sNetBiosName.GetLength()] = 0x20;
ncb.ncb_callname[NCBNAMSZ] = 0x0;
ASTAT Adapter;
ncb.ncb_buffer = (unsigned char *) &Adapter;
ncb.ncb_length = sizeof(Adapter);
uRetCode = Netbios(&ncb);