Solved

Delphi - How to Get MAC Address from Computer on LAN if I Know Its Name

Posted on 2014-01-08
15
5,258 Views
Last Modified: 2014-01-09
I know the name of another computer on the LAN. In Delphi (XE4), how can I obtain its MAC address?
0
Comment
Question by:plumothy
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 5
  • 4
  • 3
  • +2
15 Comments
 
LVL 53

Expert Comment

by:Will Szymkowski
ID: 39766871
Not sure about Delphi but you can use command prompt for this.
- open command prompt
- type arp -d
- ping <servername>
- type arp -a

This will show you the IP and MAC address of the machine you are pinging. If you are trying to get the MAC address of another computer that is on a different VLAN then you need to use a machine on the same VLAN. ARP broadcast do not go over different VLANS.

Will.
0
 

Author Comment

by:plumothy
ID: 39767256
Thanks, but I already know that. It is a Delphi function that I am after.
0
 
LVL 37

Expert Comment

by:Geert Gruwez
ID: 39767348
on about.com there is a procedure on how to do this
it uses the winsock unit to solve this

http://delphi.about.com/od/networking/l/aa103100a.htm
0
Efficient way to get backups off site to Azure

This user guide provides instructions on how to deploy and configure both a StoneFly Scale Out NAS Enterprise Cloud Drive virtual machine and Veeam Cloud Connect in the Microsoft Azure Cloud.

 

Author Comment

by:plumothy
ID: 39767370
Thanks - but that's not what I am asking for. That solution gets me my own Host Name and IP Address.

I want to to get the MAC Address of another computer (ie not mine) on the same LAN. I already know the Host Name of that other computer.
0
 
LVL 27

Expert Comment

by:Sinisa Vuk
ID: 39767377
Here you have complete function which use arp packets sent to destination computer using local net's computer name.

uses WinSock;

function SendARP(DestIp: DWORD; SrcIP: DWORD; pMacAddr: Pointer; PhyAddrLen: Pointer): DWORD;stdcall; external 'iphlpapi.dll';

function GetRemoteMacAddress(const sComputer: String; var sMacAddress: String): Boolean;
var
  WSAData : TWSAData;
  hostEnt : PHostEnt;
  sIPAddress: String;
  DestIP: Integer;
  MacAddr: array[0..5] of Byte;
  PhLen, i: Integer;
begin
  Result := False;
  sMacAddress := '';

  //initialize
  WSAStartup($101, WSAData);
  try
    //translate copmuter name to ip
    hostEnt := GetHostByName(PChar(sComputer));
    if Assigned(hostEnt) then
    begin
      if Assigned(hostEnt^.h_addr_list) then
      begin
        //if address is available?
        if Assigned(hostEnt^.h_addr_list^) then
        begin
          //format ip address
          sIPAddress := '';

          for i := 0 to hostEnt^.h_length - 1 do
            sIPAddress := Concat(sIPAddress, IntToStr(Ord(hostEnt^.h_addr_list^[i])) + '.');
          SetLength(sIPAddress, Length(sIPAddress) - 1); //trunc last point

          //translate ip address 
          DestIP := Inet_addr(PChar(sIPAddress));
          if DestIP <> INADDR_NONE then
          begin
            PhLen := SizeOf(MacAddr);
            ZeroMemory(@MacAddr[0], PhLen);
            //send arp packet and wait for response with mac address
            if SendARP(DestIP, 0, Pointer(@MacAddr[0]), @PhLen) = NO_ERROR then
            begin
              if (PhLen <> 0) then
              begin
                //format mac address
                for i := 0 to PhLen-1 do
                  sMacAddress := sMacAddress + IntToHex(MacAddr[i], 2) + '-';
                SetLength(sMacAddress, Length(sMacAddress) - 1); //trunc last -

                Result := True;
              end;
            end;
          end;
        end;
      end;
    end;
  finally
    WSACleanup;
  end;
end;

Open in new window


...should work with IPv4 and IPv6.
0
 
LVL 37

Expert Comment

by:Geert Gruwez
ID: 39767391
oops, i forgot to add the changes
here's my test unit

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Edit1: TEdit;
    Memo1: TMemo;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    fResolvedIps: TStrings;
    function IpAddress(HostName: string): string;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  end;

var
  Form1: TForm1;

implementation

uses StrUtils, Winsock;

{$R *.dfm}

function GetIPFromHost
(var HostName, IPaddr, WSAErr: string): Boolean;
type
  Name = array[0..100] of AnsiChar;
  PName = ^Name;
var
  HEnt: pHostEnt;
  HName: PName;
  WSAData: TWSAData;
  i: Integer;
  N: PAnsiChar;
begin
  Result := False;
  if WSAStartup($0101, WSAData) <> 0 then begin
    WSAErr := 'Winsock is not responding."';
    Exit;
  end;
  IPaddr := '';
  New(HName);
  for I := 1 to Length(HostName) do
    Hname^[I-1] := AnsiChar(HostName[I]);
  HName^[Length(HostName)] := #0;
  HEnt := GetHostByName(HName^);
  for i := 0 to HEnt^.h_length - 1 do
   IPaddr :=
    Concat(IPaddr,
    IntToStr(Ord(HEnt^.h_addr_list^[i])) + '.');
  SetLength(IPaddr, Length(IPaddr) - 1);
  Result := True;
  Dispose(HName);
  WSACleanup;
end;

function TForm1.IpAddress(HostName: string): string;
var aHostName, aIPaddr, aWSAErr: string;
begin
  aHostName := HostName;
  aIpAddr := '';
  aWSAErr := '';
  if GetIPFromHost(aHostName, aIpAddr, aWSAErr) then
    fResolvedIps.Values[aHostName] := aIpAddr;
  Result := fResolvedIps.Values[HostName];
  // Workaround for non-found ip adress
  //if Result = fResolvedIps.Values['localhost'] then
    //Result := '';
end;

procedure TForm1.Button1Click(Sender: TObject);
var temp: string;
begin
  Temp := IpAddress(Edit1.Text);
  if Temp = '' then
    Temp := 'Not found';
  Memo1.Lines.Add(Format('Ip Adress for %S: %S', [Edit1.Text, Temp]));
end;

constructor TForm1.Create(AOwner: TComponent);
begin
  inherited Create(aOwner);
  fResolvedIps := TStringList.Create;
  IpAddress('localhost');
end;

destructor TForm1.Destroy;
begin
  fResolvedIps.Free;
  inherited Destroy;
end;

end.

Open in new window

0
 

Author Comment

by:plumothy
ID: 39767421
Thank you guys.

sinisav: your solution does not work for me. When I run it, I get: WSANO_DATA, which MSDN tells me means: "The requested name is valid, but no data of the requested type was found. This error is also returned if the name parameter contains a string representation of an IPv6 address or an illegal IPv4 address.
This error should not be interpreted to mean that the name parameter contains a name string that has been validated for a particular protocol (an IP hostname, for example). Since Winsock supports multiple name service providers, a name may potentially be valid for one provider and not accepted by another provider."

I know that the host name I am using is correct and that it is on the LAN up and running.

Geert Gruwez: your solution runs OK and it works but it does not do what I want. It produces the host's IP address - I want its MAC address.
0
 
LVL 27

Expert Comment

by:Sinisa Vuk
ID: 39767427
Work for me in D6 on xp. I'll try in newest D. Maybe some stuff are changed.
0
 
LVL 37

Expert Comment

by:Geert Gruwez
ID: 39767457
edited, wowa, misread the q ... my excuses
0
 
LVL 27

Expert Comment

by:Sinisa Vuk
ID: 39767638
Fixed. Works in Win64 + Delphi XE3 + unicode. Won't work on XP. For XP is needed non-unicode version of structures and functions.

type
  PAddrInfo = ^TAddrInfo;
  TAddrInfo = packed record
    ai_flags: Integer;
    ai_family: Integer;
    ai_socktype: Integer;
    ai_protocol: Integer;
    ai_addrlen: LongWord;
    ai_canonname: Array of Char;
    ai_addr: PSockAddrIn;
    ai_next: PAddrInfo;
  end;

  PAddrInfoW = ^TAddrInfoW;
  TAddrInfoW = packed record
    ai_flags: integer;
    ai_family: integer;
    ai_socktype: integer;
    ai_protocol: integer;
    ai_addrlen: Cardinal;
    ai_canonname: PWideChar;
    ai_addr: PSockAddrIn;
    ai_next: PAddrInfo;
    end;

function SendARP(DestIp: DWORD; SrcIP: DWORD; pMacAddr: Pointer; PhyAddrLen: Pointer): DWORD;stdcall; external 'iphlpapi.dll';
function getaddrinfo(const nodename: PChar; const servname : PChar; const hints: PAddrInfo; var res: PAddrInfo): Integer; stdcall; external 'ws2_32.dll';
function GetAddrInfoW(nodename, servname: PWideChar; pHints: PAddrInfoW; out res: PAddrInfoW): integer; stdcall; external 'ws2_32.dll' name 'GetAddrInfoW';
procedure freeaddrinfo(ai: PAddrInfo); stdcall; external 'ws2_32.dll';
procedure FreeAddrInfoW(pai: PAddrInfoW); stdcall; external 'ws2_32.dll' name 'FreeAddrInfoW';

function GetRemoteMacAddressWin7(const sComputer: String; var sMacAddress: String): Boolean;
var
  WSAData : TWSAData;
  //sIPAddress: String;
  DestIP: Integer;
  MacAddr: array[0..5] of Byte;
  PhLen, i: Integer;
  SocketHint: TAddrInfoW;
  SocketResult: PAddrInfoW;
  //addr: in_addr;
begin
  Result := False;
  sMacAddress := '';
  WSAData.wVersion := 0;
  SocketResult := nil;
  //initialize
  WSAStartup(MakeWord(2, 0), WSAData);
  try
    //translate copmuter name to ip
    ZeroMemory(@SocketHint, sizeOf(TAddrInfoW));
    SocketHint.ai_socktype := SOCK_STREAM;
    SocketHint.ai_family := AF_UNSPEC;
    if GetAddrInfoW(PWideChar(sComputer), nil, @SocketHint, SocketResult) = 0 then
    begin
      //addr.S_un_b := SocketResult.ai_addr.sin_addr.S_un_b;
      //sIPAddress := String(inet_ntoa(addr));

      //translate ip address
      DestIP := SocketResult.ai_addr.sin_addr.S_addr;
      if DestIP <> INADDR_NONE then
      begin
        PhLen := SizeOf(MacAddr);
        ZeroMemory(@MacAddr[0], PhLen);
        //send arp packet and wait for response with mac address
        if SendARP(DestIP, 0, Pointer(@MacAddr[0]), @PhLen) = NO_ERROR then
        begin
          if (PhLen <> 0) then
          begin
            //format mac address
            for i := 0 to PhLen-1 do
              sMacAddress := sMacAddress + IntToHex(MacAddr[i], 2) + '-';
            SetLength(sMacAddress, Length(sMacAddress) - 1); //trunc last -

            Result := True;
          end;
        end;
      end;
    end;
  finally
    if Assigned(SocketResult) then FreeAddrInfoW(SocketResult);
    if WSAData.wVersion > 0 then WSACleanup;
  end;
end;

Open in new window


..NOTE: use plain symbolic name of computer like: myserver and for ip use something like:
10.20.1.33
0
 

Author Comment

by:plumothy
ID: 39767776
sinisav: thanks for trying again.

In your code, GetAddrInfoW(PWideChar(sComputer), nil, @SocketHint, SocketResult) returns WSANO_DATA which is what I was getting before.
0
 
LVL 27

Accepted Solution

by:
Sinisa Vuk earned 250 total points
ID: 39767857
Try it with:
...
SocketHint.ai_socktype := 0;
SocketHint.ai_family := 0;

Open in new window


did you try with more known computers?
-----
Try another tool as "second" opinion:
trogon-mac-scanner
0
 
LVL 19

Expert Comment

by:Thommy
ID: 39768074
Maybe that's what you are looking for...
Get MAC Address of Remote or Local Machine
0
 
LVL 19

Assisted Solution

by:Thommy
Thommy earned 250 total points
ID: 39768270
Have tried function GetMacAddress from my proposed link.

Got compile errors, because some if statements are missing the relational operators.

After inserting "<>" for the missing operators, it works fine for remote and local machines...


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
       // Silent Error
     end;
   end;

  Result := Retvar;
 end;

Open in new window

0
 

Author Closing Comment

by:plumothy
ID: 39768388
Thank you - it is working now. Points shared between sinsav and Thommy.

As suggested, I tried the "2nd opinion" tool (Trogon MAC Scanner). It failed to see any devices that were connected wirelessly and it displayed Host Name for less than one third of the computers that it found.

I was trying to find a wireless laptop. So, I connected another one with a cable. It was only then that your solutions started to work. They then found both the wired and wireless laptops (previously they were finding nothing).

I find that a bit weird and reckon that it is all rather unreliable!  Anyway, thanks for your help.
0

Featured Post

Microsoft Certification Exam 74-409

Veeam® is happy to provide the Microsoft community with a study guide prepared by MVP and MCT, Orin Thomas. This guide will take you through each of the exam objectives, helping you to prepare for and pass the examination.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Whether you've completed a degree in computer sciences or you're a self-taught programmer, writing your first lines of code in the real world is always a challenge. Here are some of the most common pitfalls for new programmers.
Although it can be difficult to imagine, someday your child will have a career of his or her own. He or she will likely start a family, buy a home and start having their own children. So, while being a kid is still extremely important, it’s also …
In this fourth video of the Xpdf series, we discuss and demonstrate the PDFinfo utility, which retrieves the contents of a PDF's Info Dictionary, as well as some other information, including the page count. We show how to isolate the page count in a…
In this fifth video of the Xpdf series, we discuss and demonstrate the PDFdetach utility, which is able to list and, more importantly, extract attachments that are embedded in PDF files. It does this via a command line interface, making it suitable …

740 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question