如何在win98下取得网卡物理地址?(150分)

  • 主题发起人 主题发起人 lfzxs
  • 开始时间 开始时间
给你一段代码,你参考。是别人的代码。
整套软件可以发给你,应该可以得到你要的。
{
(c)2001 zw84611
this unit do the samce thing as dos command "nbtstat -a ip".

This is not a vcl component, it's just a unit, needn't install.
}
unit Nbtstat;

interface

uses
Windows, Messages, SysUtils, Classes, Controls, Dialogs, WinSock, ComCtrls, Forms;

const
WM_SOCK = WM_USER + 1; //自定义windows消息
//UDPPORT = 6767; //设定UDP端口号
NBTPORT = 137; //NAME_SERVICE_UDP_PORT 137 (decimal) (RFC1002)

type
TNbt = class(TComponent)
private
s: TSocket;
addr: TSockAddr;
FSockAddrIn : TSockAddrIn; //利用消息实时获知UDP消息
FHandle: HWnd; //非可视构件消息处理使用
procedure ReadData(var Message: TMessage); //message WM_SOCK;
procedure RecvNbMsg(buffer: array of byte;len:integer;IP:string);
procedure SendData(b:array of byte;IP:string);
public
wait_time: integer;
StartIP, EndIP: string;
StatusString: string;
MyListView: TListView;
OnEndEvent: TNotifyEvent;
OnSendEvent: TNotifyEvent;
OnAddNodeEvent: TNotifyEvent;
//RootTreeNode: TTreeNode;

constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
procedure Start;
procedure Stop;
procedure Pause;
procedure Restart;

end;

TSendDataThread=class(TThread)
private
IP, IP1, IP2: string;
protected
procedure Execute; override;
procedure GetIP;
procedure Send;
procedure OnExit;
end;

var
Nbt: TNbt;
B1,B2: array [0..3]of byte;
SendDataThread: TSendDataThread;
WAIT_ACK_EVENT: Thandle;
exit_nbt_thread: boolean;

implementation
//uses FmxUtils; // IsLegalIP
{
function IsLegalIP(IP:string):boolean;
begin

if Longword(inet_addr(pchar(IP)))=INADDR_NONE then
begin
result:=false;
exit;
end
else result:=true;

end;
}

{
procedure GetAddrByte(IP:string;var B:array of byte);
var i,j:integer;
s:string;
begin

s:='';
j:=0;
IP:=IP+'.';
for i:=1 to length(IP)do
begin
if IP<>'.' then s:=s+IP
else
begin
B[j]:=byte(strtoint(s));
inc(j);
s:='';
end;
end;

end;
}

procedure TSendDataThread.Send;
{
RFC1002: " PROTOCOL STANDARD FOR A NetBIOS SERVICE ON A TCP/UDP TRANSPORT:
DETAILED SPECIFICATIONS "

4.2.17. NODE STATUS REQUEST

1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| NAME_TRN_ID |0| 0x0 |0|0|0|0|0 0|B| 0x0 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 0x0001 | 0x0000 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 0x0000 | 0x0000 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
/ QUESTION_NAME /
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| NBSTAT (0x0021) | IN (0x0001) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
}
const NbtstatPacket:array[0..49]of byte
=($0,$0,$0,$0,$0,$1,
$0,$0,$0,$0,$0,$0,$20,$43,$4b,
$41,$41,$41,$41,$41,$41,$41,$41,
$41,$41,$41,$41,$41,$41,$41,$41,
$41,$41,$41,$41,$41,$41,$41,$41,
$41,$41,$41,$41,$41,$41,$0,$0,$21,$0,$1);
begin

Nbt.StatusString := '正在测试:' + IP;
if assigned(Nbt.OnSendEvent) then Nbt.OnSendEvent(nil);
Nbt.SendData(NbtstatPacket, IP);

end;

procedure TSendDataThread.GetIP;
begin

IP1 := Nbt.StartIP;
IP2 := Nbt.EndIP;

end;

procedure TSendDataThread.OnExit;
begin

if assigned(Nbt.OnEndEvent) then Nbt.OnEndEvent(nil);

end;

procedure TSendDataThread.Execute;
var
nIP1, nIP2, i: dword;
begin

Synchronize(GetIP);

{if (not IsLegalIP(IP1))or(not IsLegalIP(IP2)) then
begin
ShowMessage('Illegal IP address!');
exit;
end; }

//GetAddrByte(IP,B1);
//GetAddrByte(IP2,B2);
nIP1 := ntohl(inet_addr(pchar(IP1)));
nIP2 := ntohl(inet_addr(pchar(IP2)));

for i := nIP1 to nIP2 do
begin
if exit_nbt_thread then
begin
Synchronize(OnExit);
exit;
end;

//去掉x.x.x.0或x.x.x.255的地址。
if (((i - 255) mod 256)=0)or((i mod 256)=0) then continue;

IP := inet_ntoa(in_addr(htonl(i)));
Synchronize(Send);

WaitForSingleObject(WAIT_ACK_EVENT,Nbt.wait_time);
ResetEvent(WAIT_ACK_EVENT);
end;
{
repeat

if exit_thread then
begin
Synchronize(OnExit);
exit;
end;
IP:=format('%d.%d.%d.%d',[B1[0],B1[1],B1[2],B1[3]]);
Synchronize(Send);

WaitForSingleObject(WAIT_ACK_EVENT,Nbt.wait_time);
ResetEvent(WAIT_ACK_EVENT);

if(B1[2]<=B2[2]) then
begin
if(B1[3]<B2[3]) then inc(B1[3])
else if((B1[2]<B2[2]) and (B1[3]<255))then inc(B1[3])
else if((B1[2]<B2[2]) and (B1[3]=255)) then
begin
B1[3]:=1;
inc(B1[2]);
end;
end
else break;
if((B1[3]>=B2[3]) and (B1[2]>=B2[2])) then break;

until ((B1[2]=255));// or (B1[3]=255));
}

Synchronize(OnExit);

end;

constructor TNbt.Create(AOwner: TComponent);
var
TempWSAData: TWSAData;
//optval: integer;
begin

inherited Create(AOwner);
FHandle := AllocateHWnd(ReadData); //attention here.


// 初始化SOCKET
if WSAStartup($101, TempWSAData)=1 then
showmessage('StartUp Error!');

s := Socket(AF_INET, SOCK_DGRAM, 0);
if (s = INVALID_SOCKET) then //Socket创建失败
begin
ShowMessage(inttostr(WSAGetLastError())+' Socket创建失败');
CloseSocket(s);
end;
//本机SockAddr绑定
addr.sin_family := AF_INET;
addr.sin_addr.S_addr := INADDR_ANY;
//addr.sin_port := htons(UDPPORT);
if Bind(s, addr, sizeof(addr)) <> 0 then
begin
showmessage('bind fail');
end;
WSAAsyncSelect(s, FHandle , WM_SOCK, FD_READ);
//对方SockAddrIn设定
FSockAddrIn.SIn_Family := AF_INET;
FSockAddrIn.SIn_Port := htons(NBTPORT);

WAIT_ACK_EVENT:=CreateEvent(nil,true,false,pchar('WAIT_ACK'));
//ResetEvent(WAIT_ACK_EVENT);
wait_time:=100;

end;

destructor TNbt.Destroy;
begin

CloseSocket(s);
WSACleanup();
DeallocateHWnd(FHandle);
inherited Destroy;

end;

procedure TNbt.RecvNbMsg(buffer: array of byte;len:integer;IP:string);
var
str:string;
i,j,pos,name_num: integer;
item : TListItem;
begin

item:=MyListView.Items.Insert(0);
item.Caption := IP;
for i:=0 to 4 do item.SubItems.Add(''); // attention: we do like item.SubItems[3]:=str;

{
RFC1002: " PROTOCOL STANDARD FOR A NetBIOS SERVICE ON A TCP/UDP TRANSPORT:
DETAILED SPECIFICATIONS "

4.2.18. NODE STATUS RESPONSE

1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| NAME_TRN_ID |1| 0x0 |1|0|0|0|0 0|0| 0x0 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 0x0000 | 0x0001 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 0x0000 | 0x0000 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
/ RR_NAME /
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| NBSTAT (0x0021) | IN (0x0001) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 0x00000000 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| RDLENGTH | NUM_NAMES | |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +
| |
+ +
/ NODE_NAME ARRAY /
+ +
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
+ +
/ STATISTICS /
+ +
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

The NODE_NAME ARRAY is an array of zero or more NUM_NAMES entries
of NODE_NAME records. Each NODE_NAME entry represents an active
name in the same NetBIOS scope as the requesting name in the
local name table of the responder. RR_NAME is the requesting
name.

NODE_NAME Entry:

1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
+--- ---+
| |
+--- NETBIOS FORMAT NAME ---+
| |
+--- ---+
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| NAME_FLAGS |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

The NAME_FLAGS field:

1 1 1 1 1 1
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
| G | ONT |DRG|CNF|ACT|PRM| RESERVED |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+

The NAME_FLAGS field is defined as:

Symbol Bit(s) Description:

RESERVED 7-15 Reserved for future use. Must be zero (0).
PRM 6 Permanent Name Flag. If one (1) then entry
is for the permanent node name. Flag is zero
(0) for all other names.
ACT 5 Active Name Flag. All entries have this flag
set to one (1).
CNF 4 Conflict Flag. If one (1) then name on this
node is in conflict.
DRG 3 Deregister Flag. If one (1) then this name
is in the process of being deleted.
ONT 1,2 Owner Node Type:
00 = B node
01 = P node
10 = M node
11 = Reserved for future use
G 0 Group Name Flag.
If one (1) then the name is a GROUP NetBIOS
name.
If zero (0) then it is a UNIQUE NetBIOS name.


STATISTICS Field of the NODE STATUS RESPONSE:

1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| UNIT_ID (Unique unit ID) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| UNIT_ID,continued | JUMPERS | TEST_RESULT |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| VERSION_NUMBER | PERIOD_OF_STATISTICS |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| NUMBER_OF_CRCs | NUMBER_ALIGNMENT_ERRORS |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| NUMBER_OF_COLLISIONS | NUMBER_SEND_ABORTS |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| NUMBER_GOOD_SENDS |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| NUMBER_GOOD_RECEIVES |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| NUMBER_RETRANSMITS | NUMBER_NO_RESOURCE_CONDITIONS |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| NUMBER_FREE_COMMAND_BLOCKS | TOTAL_NUMBER_COMMAND_BLOCKS |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|MAX_TOTAL_NUMBER_COMMAND_BLOCKS| NUMBER_PENDING_SESSIONS |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| MAX_NUMBER_PENDING_SESSIONS | MAX_TOTAL_SESSIONS_POSSIBLE |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| SESSION_DATA_PACKET_SIZE |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
}

name_num:=0;
for i:=1 to len do
begin
if((buffer=$21)and(buffer[i+1]=$00)and(buffer[i+2]=$01))
then
begin
name_num:=buffer[i+9];
break;
end;
end;
if name_num=0 then exit;
pos:=i+10;

str:='';
for i:=pos to (pos+18*name_num-1) do
begin
if (((i-pos)mod 18) =0) then
begin
for j:=0 to 14 do
begin
if trim(char(buffer[i+j]))='' then buffer[i+j]:=ord(' ');
str:=str+char(buffer[i+j]);
end;
if (buffer[i+16] and $80)=$80 then
begin
if buffer[i+15]=$0 then item.SubItems[0]:=str;

str:=str+format('<%x>',[buffer[i+15]]);
str:=str+'<GROUP>';
end
else
begin
if buffer[i+15]=$20 then item.SubItems[1]:=str
else
if buffer[i+15]=$3 then item.SubItems[2]:=str;

str:=str+format('<%x>',[buffer[i+15]]);
str:=str+'<UNIQUE>';
end;
//ListBox1.Items.Add(str);
str:='';
end;
end;

for i:=0 to 5 do
begin
str:=str+format('%.2x.',[buffer[i+pos+18*name_num]]);
end;
delete(str,length(str),1);
item.SubItems[3]:=str;

//----------------------------------------------------
if assigned(OnAddNodeEvent) then OnAddNodeEvent(TObject(IP));

end;

procedure TNbt.ReadData(var Message: TMessage);
var
buffer: Array [1..500] of byte;
flen,len: integer;
Event: word;
IP:string;
begin
if Message.msg<>WM_SOCK then exit;
//Windows.Beep(2000,200);
flen:=sizeof(FSockAddrIn);
FSockAddrIn.SIn_Family := AF_INET;
FSockAddrIn.SIn_Port := htons(NBTPORT);
Event := WSAGetSelectEvent(Message.LParam);
if Event = FD_READ then
begin
len := recvfrom(s, buffer, sizeof(buffer), 0, FSockAddrIn, flen);
if len> 0 then
begin

//FSockAddrIn.sin_addr.S_un_b.s_b1
with FSockAddrIn.sin_addr.S_un_b
do IP:=format('%d.%d.%d.%d',[ord(s_b1),ord(s_b2),ord(s_b3),ord(s_b4)]);

RecvNbMsg(buffer,len,IP);

end;
SetEvent(WAIT_ACK_EVENT);

end;

end;

procedure TNbt.SendData(b:array of byte;IP:string);
var
len: integer;
begin

FSockAddrIn.SIn_Addr.S_addr := inet_addr(pchar(IP));
FSockAddrIn.SIn_Family := AF_INET;
FSockAddrIn.SIn_Port := htons(NBTPORT);
len := sendto(s, b[0],50, 0, FSockAddrIn, sizeof(FSockAddrIn));
//if (WSAGetLastError() <> WSAEWOULDBLOCK) and (WSAGetLastError() <> 0) then showmessage(inttostr(WSAGetLastError()));
if len = SOCKET_ERROR then
if Application.MessageBox(
'SOCKET错误,可能是你网线没接好或网络设置有问题,是否中断扫描?',
'SOCKET ERROR',
MB_OKCANCEL + MB_DEFBUTTON1) = IDOK then exit_nbt_thread := true;

{if len <> 50 then
showmessage('Not Send all');}
end;

procedure TNbt.start;
begin

exit_nbt_thread := false;
SendDataThread := TSendDataThread.Create(true);
SendDataThread.FreeOnTerminate := true;
SendDataThread.Resume;

end;

procedure TNbt.Stop;
begin
exit_nbt_thread := true;
SendDataThread.Terminate;
end;

procedure TNbt.Pause;
begin
SendDataThread.Suspend;
end;

procedure TNbt.Restart;
begin
SendDataThread.Resume;
end;

end.
 
好复杂啊
我认真看一下
 
接受答案了.
 
后退
顶部