/ ======================================================================
//返回值是主机AServerName的MAC地址
//AServerName参数的格式为'\\ServerName' 或者 'ServerName'
//参数ServerName为空时返回本机的MAC地址
//MAC地址以'XX-XX-XX-XX-XX-XX'的格式返回
// ======================================================================function GetMacAddress(const AServerName: string): string;
type
  TNetTransportEnum = function(pszServer: PWideChar;
    Level: DWORD;
    var pbBuffer: pointer;
    PrefMaxLen: LongInt;
    var EntriesRead: DWORD;
    var TotalEntries: DWORD;
    var ResumeHandle: DWORD): DWORD; stdcall;  TNetApiBufferFree = function(Buffer: pointer): DWORD; stdcall;  PTransportInfo = ^TTransportInfo;
  TTransportInfo = record
    quality_of_service: DWORD;
    number_of_vcs: DWORD;
    transport_name: PWChar;
    transport_address: PWChar;
    wan_ish: boolean;
  end;var
  E, ResumeHandle,
    EntriesRead,
    TotalEntries: DWORD;
  FLibHandle: THandle;
  sMachineName,
    sMacAddr,
    Retvar: string;
  pBuffer: pointer;
  pInfo: PTransportInfo;
  FNetTransportEnum: TNetTransportEnum;
  FNetApiBufferFree: TNetApiBufferFree;
  pszServer: array[0..128] of WideChar;
  i, ii, iIdx: integer;
begin
  sMachineName := trim(AServerName);
  Retvar := '00-00-00-00-00-00';  // Add leading \\ if missing
  if (sMachineName <> '') and (length(sMachineName) >= 2) then
  begin
    if copy(sMachineName, 1, 2) <> '\\' then
      sMachineName := '\\' + sMachineName
  end;  // Setup and load from DLL
  pBuffer := nil;
  ResumeHandle := 0;
  FLibHandle := LoadLibrary('NETAPI32.DLL');  // Execute the external function
  if FLibHandle <> 0 then
  begin
    @FNetTransportEnum := GetProcAddress(FLibHandle, 'NetWkstaTransportEnum');
    @FNetApiBufferFree := GetProcAddress(FLibHandle, 'NetApiBufferFree');
    E := FNetTransportEnum(StringToWideChar(sMachineName, pszServer, 129), 0,
      pBuffer, -1, EntriesRead, TotalEntries, Resumehandle);    if E = 0 then
    begin
      pInfo := pBuffer;      // Enumerate all protocols - look for TCPIP
      for i := 1 to EntriesRead do
      begin
        if pos('TCPIP', UpperCase(pInfo^.transport_name)) <> 0 then
        begin
          // Got It - now format result 'xx-xx-xx-xx-xx-xx'
          iIdx := 1;
          sMacAddr := pInfo^.transport_address;          for ii := 1 to 12 do
          begin
            Retvar[iIdx] := sMacAddr[ii];
            inc(iIdx);
            if iIdx in [3, 6, 9, 12, 15] then inc(iIdx);
          end;
        end;        inc(pInfo);
      end;
      if pBuffer <> nil then FNetApiBufferFree(pBuffer);
    end;    try
      FreeLibrary(FLibHandle);
    except
      // 错误处理
    end;
  end;
  result := Retvar;
end;

解决方案 »

  1.   

    NetWkstaTransportEnum这个函数到底是起什么作用的?适用于什么情况?
    E := FNetTransportEnum(StringToWideChar(sMachineName, pszServer, 129), 0,
          pBuffer, -1, EntriesRead, TotalEntries, Resumehandle);这个返回的值的作用我用这段代码能够得到本机的mac地址,但是不能得到远程机器的mac地址,请问有其他更好的办法吗?
      

  2.   

    unit Unit1;
    interfaceuses
      Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, winsock,
      StdCtrls;const
      WM_SOCK = WM_USER + 1;     //自定义windows消息
      UDPPORT = 6767;            //设定UDP端口号
      NBTPORT = 137;type
      TForm1 = 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);    procedure GetInfo(buffer: Array of byte;len:integer);
      end;var
      Form1: TForm1;implementation{$R *.DFM}procedure TForm1.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, Form1.Handle , WM_SOCK, FD_READ);
         //对方SockAddrIn设定
         FSockAddrIn.SIn_Family := AF_INET;
         FSockAddrIn.SIn_Port := htons(NBTPORT);
    end;procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
    begin
        CloseSocket(s);
    end;procedure TForm1.GetInfo(buffer: Array of byte;len:integer);
    var
        str:string;
        i,j,pos,name_num: integer;
    begin  name_num:=0;
      for i:=1 to len do
      begin
        if((buffer[i]=$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
          str:=str+format('<%x>',[buffer[i+15]]);
          str:=str+'<GROUP>';
          ListBox1.Items.Add(str);
        end
        else
        begin
          str:=str+format('<%x>',[buffer[i+15]]);
          str:=str+'<UNIQUE>';
          ListBox1.Items.Add(str);
        end;
        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);
      str:='MAC:'+str;
      ListBox1.Items.Add(str);
      ListBox1.Items.Add('------------------------------------------------------');
      ListBox1.TopIndex :=ListBox1.Items.count-1;end;procedure TForm1.ReadData(var Message: TMessage);
    var
       buffer: Array [1..500] of byte;
       len{,i}: integer;
       flen: integer;
       Event: word;
       value: string;begin
         value:='';
         flen:=sizeof(FSockAddrIn);
         FSockAddrIn.SIn_Port := htons(NBTPORT);
         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,len);
         end;
    end;procedure TForm1.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 TForm1.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;end.窗口加这三个控件:TButton;TListBox;TEdit;   Button1: TButton;   ListBox1: TListBox;    Edit1: TEdit;联上3个过程:
        procedure FormCreate(Sender: TObject);
        procedure FormClose(Sender: TObject; var Action: TCloseAction);
        procedure Button1Click(Sender: TObject);
      

  3.   

    远程机器的MAC查询function SendARP(DestIP: DWORD; SrcIP: DWORD; pMacAddr: PDWORD;
      var PhyAddrLen: DWORD): DWORD;
      stdcall; external 'IPHlpAPI.DLL';function GetRemoteMACAddress(DestIP: string): string;
    type
      TInfo = array[0..7] of BYTE;
    var
      dwTargetIP: DWORD;
      dwMacAddress: array[0..1] of DWORD;
      dwMacLen: DWORD;
      dwResult: DWORD;
      X: TInfo;
    begin
      dwTargetIP := Inet_Addr(PChar(DestIP));
      dwMacLen := 6;
      dwResult := SendARP(dwTargetIP, 0, @dwMacAddress[0], dwMacLen);
      if dwResult = NO_ERROR then
      begin
        X := TInfo(dwMacAddress);
        Result := Format('%x%x%x%x%x%x',
          [X[0], X[1], X[2], X[3], X[4], X[5]]);
      end;
    end;
      

  4.   

    这里还有一个
    http://search.csdn.net/Expert/topic/683/683119.xml?temp=.9414026
      

  5.   

    NetWkstaTransportEnumThe NetWkstaTransportEnum function supplies information about transport protocols that are managed by the redirector, which is the software on the client computer that generates file requests to the server computer.Security Requirements
    No special group membership is required to successfully execute NetWkstaTransportEnum.NET_API_STATUS NetWkstaTransportEnum(
      LPWSTR servername,    
      DWORD level,          
      LPBYTE *bufptr,       
      DWORD prefmaxlen,     
      LPDWORD entriesread,  
      LPDWORD totalentries, 
      LPDWORD resumehandle  
    );
     
    Parameters
    servername 
    Ppointer to a Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer. 
    level 
    Specifies the following value to return the level of information provided. Value Meaning 
    0 The bufptr parameter points to a WKSTA_TRANSPORT_INFO_0 structure. 
    bufptr 
    On return a pointer to the return information structure is returned in the address pointed to by bufptr. 
    prefmaxlen 
    Preferred maximum length, in 8-bit bytes of returned data. 
    entriesread 
    Pointer to a DWORD that contains the actual enumerated element count. 
    totalentries 
    Pointer to a DWORD that contains the total number of entries that could have been enumerated from the current resume position. 
    resumehandle 
    Pointer to a DWORD that contains resumehandle, which is used to continue an existing workstation transport search. The handle should be zero on the first call and left unchanged for subsequent calls. If resumehandle is NULL, no resume handle is stored. 
    Return Values
    If the function is successful, it returns NERR_SUCCESS.If the function fails, the return value is one of the following error codes.Value Meaning 
    ERROR_MORE_DATA Additional information is available. 
    ERROR_INVALID_LEVEL The level parameter, which indicates what level of data structure information is available, is invalid. 
      

  6.   

    谢谢你从Delphi的帮助中复制了它,辛苦了!
    但这个仍然不能解决我的问题!
      

  7.   

    >>NetWkstaTransportEnum这个函数到底是起什么作用的?适用于什么情况?NetWkstaTransportEnum 應該是收集指定計算機有關網絡協議方面的信息
    你想查詢指定計算機的信息就可用這個函數
      

  8.   

    >>这个返回的值的作用
    返回的值, 告訴你這個函數執行成功與否, 如果是:
    NERR_Success 就是執行成功了, 如果是:
    ERROR_MORE_DATA 就是你的緩衝區不夠大ERROR_INVALID_LEVEL  你的level 設置有問題
      

  9.   

    >>我用这段代码能够得到本机的mac地址,但是不能得到远程机器的mac地址不大确定, 也許是權限不夠
      

  10.   

    回复人: ksaiy(消失在人海-喜欢昆明的花) ( ) 信誉:100  2004-11-04 16:14:00  得分: 0  
    你的第二段代码能够得到本网段内机器的MAC地址,但是对于通过路由器的外网段机器无法的到!
    怎么回事?
      

  11.   

    远程机器的你可以用我给你贴的第一段或是:http://search.csdn.net/Expert/topic/683/683119.xml?temp=.9414026
      

  12.   

    给你的第一段是UDP的。网址那段是SNMP的。
      

  13.   

    我觉得你用UDP实现更简单一点。
      

  14.   

    我的QQ号码是63194627
    ksaiy(消失在人海-喜欢昆明的花) ( ) 信誉:100 你可以加我吗?
    以后我可以向您请教问题!
      

  15.   

    SNMP那段程序实在看太不懂!
    可惜!
      

  16.   


    http://www.delphibox.com/article.asp?articleid=327    局域网搜索软件。方便快捷地搜索、浏览局域网资源。多线程搜索局域网上所有的工作组、主机、打印机、共享文件。自动搜索所有共享的mp3、电影或自定义搜索的文件;允许用户自己设置登录的用户名密码。包括默认值和对不同的主机设置不同的值;内置nbtstat,能快速查找某一IP网段内的所有主机,并根据IP地址得到对方主机的主机名、工作组名、用户名、MAC地址,速度极快。并方便地访问其资源。能对某一地址范围的主机进行ping,端口扫描操作,找出所有的WEB服务器,FTP服务器等。能向某一主机发送消息。提供断点续传的功能(局域网机器间拷贝文件时)。