要用到nb30单元
function TForm1.Getmac:string;
var
  ncb : TNCB;
  s:string;
  adapt : TASTAT;
  lanaEnum : TLanaEnum;
  i, j, m : integer;
  strPart, strMac : string;
begin
FillChar(ncb, SizeOf(TNCB), 0);
  ncb.ncb_command := Char(NCBEnum);
  ncb.ncb_buffer := PChar(@lanaEnum);
  ncb.ncb_length := SizeOf(TLanaEnum);
  s:=Netbios(@ncb);
  for i := 0 to integer(lanaEnum.length)-1 do
  begin
    FillChar(ncb, SizeOf(TNCB), 0);
    ncb.ncb_command := Char(NCBReset);
    ncb.ncb_lana_num := lanaEnum.lana[i];
    Netbios(@ncb);
    Netbios(@ncb);
    FillChar(ncb, SizeOf(TNCB), 0);
    ncb.ncb_command := Chr(NCBAstat);
    ncb.ncb_lana_num := lanaEnum.lana[i];
    ncb.ncb_callname := '*               ';
    ncb.ncb_buffer := PChar(@adapt);
    ncb.ncb_length := SizeOf(TASTAT);
    m:=0;
    if (Win32Platform = VER_PLATFORM_WIN32_NT) then
    m:=1;
    if m=1 then
    begin
    if Netbios(@ncb) = Chr(0) then
      strMac := '';
      for j := 0 to 5 do
      begin
        strPart := IntToHex(integer(adapt.adapter.adapter_address[j]), 2);
        strMac := strMac + strPart + '-';
      end;
      SetLength(strMac, Length(strMac)-1);
    end;
  if m=0 then
    if Netbios(@ncb) <> Chr(0) then
    begin
      strMac := '';
      for j := 0 to 5 do
      begin
        strPart := IntToHex(integer(adapt.adapter.adapter_address[j]), 2);
        strMac := strMac + strPart + '-';
      end;
      SetLength(strMac, Length(strMac)-1);
    end;
  end;
result:=strmac;
end;

解决方案 »

  1.   

    请问:如何实现网卡的物理地址和IP地址的相互查询 (即在局域网内,知道IP查MAC地址,知道MAC地址查IP)
    你可以使用arp程序(WINDOWS自带)
    eg: arp -a 192.168.0.1如果使用程序查的话,你需要去实现一个ARP、RARP协议的软件
    如果只是查看一下对应关系,可以登陆到以太网交换机上查看IP和MAC之间的对应
    在Windows9x中,可按如下思路进行:
    1、建立局域网内IP地址--MAC地址对照表:
      调用icmp.dll中的IcmpSendEcho函数对一个地址发一个ping操作。
      成功后马上调用Iphlpapi.dll中的GetIpNetTable函数来取所有的ARP表,从中找出
    所关心的MAC地址。
      保存IP地址和MAC地址。
      依此类推,取得局域网内所有IP地址和MAC地址的对照表。
      (可取范围为IPADDR and SUBMASK 子网范围内的对照表)
    2、做一个查询界面。Windows2000中,应该可以更简单一些。因为它支持更多的函数如SendARP。
    IP to MAC 较容易:
    方法1. DOS命令: nbtstat -a IP
    方法2. DOS命令: ping IP 然后 arp -a
    方法3. 仿照nbtstat,向对方的137端口发数据包,包的内容如下(C代码)
     BYTE b[50]={0x0,0x00,0x0,0x10,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,
                 0x20,0x43,0x4b,0x41,0x41,0x41,0x41,0x41,0x41,0x41,
                 0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,
                 0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,
                 0x41,0x41,0x41,0x0,0x0,0x21,0x0,0x1};
     (这是发nbtstat命令后用IPMan截获的),对方会向你返回一个数据包,
     其中有对方的工作组,主机名,用户名,MAC地址。当然,返回包的格式要
     自己分析,也可以查RFC文档。你自己的端口可以随便取一个值。
    方法4.在win9x下可用IPMan直接发ARP。
    方法5.在win2000下可用SendArp()直接发ARP。
    ----------------------------------------------------------------
    MAC to IP似乎较困难。
    Win9x下IPMan有此项功能,但我试了一下似乎不行。
    来自:zw84611, 时间:2001-10-7 19:37:00, ID:659172 
    发出去了,是用VC写的。因为我不喜欢Delphi5 的udp控件。其实用delphi也一样。很
    简单的,就是向对方137端口发内容为
    BYTE b[50]={0x0,0x00,0x0,0x10,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,
                 0x20,0x43,0x4b,0x41,0x41,0x41,0x41,0x41,0x41,0x41,
                 0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,
                 0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,
                 0x41,0x41,0x41,0x0,0x0,0x21,0x0,0x1};
    的UDP包(Delphi中用$代替0x),对方就会给你应答,你接收就是了。
     
    Delphi源码如下,其中UDP用Socket API实现。
    -------------------------------------------------------unit udp;interfaceuses
      Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, winsock,
      StdCtrls;const
      WM_SOCK = WM_USER + 1;     //自定义windows消息
      UDPPORT = 6767;            //设定UDP端口号
      NBTPORT = 137;type
      Tfrmmain = class(TForm)
        Button1: TButton;
        ListBox1: TListBox;
        Edit1: TEdit;
        procedure FormCreate(Sender: TObject);
        procedure FormClose(Sender: TObject; var Action: TCloseAction);
        procedure Button1Click(Sender: TObject);
      private
        { Private declarations }
        s: TSocket;
        addr: TSockAddr;
        FSockAddrIn : TSockAddrIn; //利用消息实时获知UDP消息
        procedure ReadData(var Message: TMessage); message WM_SOCK;
      public
        { Public declarations }
        procedure SendData(b:array of byte);
      end;var
      frmmain: Tfrmmain;implementation{$R *.DFM}procedure Tfrmmain.FormCreate(Sender: TObject);
    var
       TempWSAData: TWSAData;
       //optval: integer;
    begin
         // 初始化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, frmmain.Handle , WM_SOCK, FD_READ);
         //对方SockAddrIn设定
         FSockAddrIn.SIn_Family := AF_INET;
         FSockAddrIn.SIn_Port := htons(NBTPORT);
    end;procedure Tfrmmain.FormClose(Sender: TObject; var Action: TCloseAction);
    begin
        CloseSocket(s);
    end;procedure GetInfo(buf: Array of byte);
    {这个过程是根据返回报文的内容凑出来的,偶尔会出错。如果能根据
    报文格式的定义来做(可查阅相关RFC文档,可惜我没时间,以后做吧),就更好了。
    如果你作出来了,不妨寄给我一个哟。e-mail:[email protected]}
    var bAdd,bMac:boolean;
        str,strHost,strHex,strMac:string;
        tem,i,j:integer;
    begin  bAdd:=true;
      strHost:='';
      strHex:='';
      tem:=0;
      for i:=57 to 500 do //57-72
      begin
        if(Buf[i]=$cc)then break;
        if(Buf[i]=$20)then bAdd:=false;
        if(bAdd)then
        begin
          str:=char(Buf[i]);
          strHost:=strHost+str;      str:=Format('%x.',[Buf[i]]);
          strHex:=strHex+str;
        end;    inc(tem);
        if(tem mod 18=0)then
        begin
          bAdd:=true;
          Trim(strHex);
          bMac:=true;
          for j:=1 to length(strHex) do if strHex[j]>'0' then bMac:=false;
          //showmessage(strHex);
          if(bMac)then
          with frmmain.ListBox1 do
          begin
            Items.Delete(items.count-1);
            Items.add('mac address:');
            Delete(strMac,17,length(strMac)-17);
            Items.Add(strMac);
            break;
          end;
          frmmain.ListBox1.items.Add(strHost);
          strMac:=strHex;
          strHost:='';
          strHex:='';
        end;
      end;end;procedure Tfrmmain.ReadData(var Message: TMessage);
    var
       buffer: Array [1..500] of byte;
       len{,i}: integer;
       flen: integer;
       Event: word;
       value: string;begin
         value:='';
         Event := WSAGetSelectEvent(Message.LParam);
         if Event = FD_READ then
         begin
              len := recvfrom(s, buffer, sizeof(buffer), 0, FSockAddrIn, flen);
              {for i:=1 to len do value:=value+format('%x',[buffer[i]]);
              ListBox1.items.add(value);
              value:='';
              for i:=1 to len do if char(buffer[i])<>#0 then value:=value+char(buffer[i]);
              ListBox1.items.add(value);}
              if len<> 0 then GetInfo(buffer);
         end;
    end;procedure Tfrmmain.SendData(b:array of byte);
    var
       len: integer;
    begin     FSockAddrIn.SIn_Addr.S_addr := inet_addr(pchar(edit1.text));
         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
            showmessage('send fail');
         if len <> 50 then
            showmessage('Not Send all');
    end;procedure Tfrmmain.Button1Click(Sender: TObject);
    const NbtstatPacket:array[0..49]of byte
          =($0,$0,$0,$10,$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  senddata(NbtstatPacket);
      
    end;