Delphi XE5 で PING を使ってみる

IndyIdIcmpClient.Ping() を使う場合は、exe を管理者権限で実行する必要があるようです。
ネット上に、Winsock を使ったサンプルがあったので、試してみました。


unit xpingUnit;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Winsock, Vcl.StdCtrls;

type
  TForm1 = class(TForm)
    Memo1: TMemo;
    Button1: TButton;
    Edit1: TEdit;
    Edit2: TEdit;
    Button2: TButton;
    Label1: TLabel;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
    runFlag : boolean;
  end;

var
  Form1: TForm1;

  // icmp.dll
  function IcmpCreateFile : THandle; stdcall; external 'icmp.dll';
  function IcmpCloseHandle (icmpHandle : THandle) : boolean; stdcall; external 'icmp.dll';
  function IcmpSendEcho (
    IcmpHandle : THandle;
    DestinationAddress : TInAddr;
    RequestData : Pointer; RequestSize : Smallint;
    RequestOptions : Pointer;
    ReplyBuffer : Pointer;
    ReplySize : DWORD;
    Timeout : DWORD) : DWORD; stdcall; external 'icmp.dll';

implementation

{$R *.dfm}

// -----------------------------------------------
// uses Winsock
// http://homepage1.nifty.com/MADIA/delphi/delphi_bbs/200607/200607_06070018.html
// 「同一LAN内のIPAdressやMacAdressを取得するには?」
// ほぼ、そのままのコードです。
// -----------------------------------------------

// IP アドレスからホスト名を得る
function GetHostName(Ip : AnsiString) : AnsiString;
var
  PH : PHostEnt;
  InAddr: TInAddr;
  WSADATA : TWSADATA;
begin
  Result := '';
  if Ip = '' then Exit;
  InAddr.S_addr := inet_addr(PAnsiChar(Ip));
  WSAStartup(MakeWord(1, 1) , WSADATA);  //MakeWord(1,1)=$0101

  PH := GetHostByAddr(@InAddr, 4, PF_INET);

  if PH = nil then Exit;
  Result := AnsiString(PH^.h_name);
  WSACleanup;
end;

// ホスト名から IP アドレスを得る
function GetIpAddress(HostName : AnsiString) : AnsiString;
var
  PH : PHostEnt;
  InAddr: TInAddr;
  WSADATA : TWSADATA;
begin
  Result := '';
  if HostName = '' then Exit;
  WSAStartup(MakeWord(1, 1), WSADATA);

  PH := GetHostByName(PAnsiChar(HostName));

  if PH = nil then Exit;
  InAddr := PInAddr(PH^.h_addr_list^)^;
  Result := inet_ntoa(InAddr);
  WSACleanup;
end;
// PING
function PingIP(Ip : Ansistring) : boolean;
var
  Hnd : THandle;
  InAddr : TInAddr;
  DW : DWORD;
  rep : array [1..128] of byte;
begin
  result := false;
  Hnd := IcmpCreateFile;
  if Hnd = INVALID_HANDLE_VALUE then Exit;

  InAddr.S_addr := inet_addr(PAnsiChar(Ip));
  DW := IcmpSendEcho(Hnd, InAddr, nil, 0, nil, @rep, 128, 500{Timeout});
  Result := DW <> 0;
  IcmpCloseHandle(Hnd);
end;

// 自PCのIPアドレスとPC名を取得
function LocalIP(var PcName: AnsiString): Ansistring;
type
  TaPInAddr = array [0..10] of PInAddr;
  PaPInAddr = ^TaPInAddr;
var
  PH : PHostEnt;
  pPtr: PaPInAddr;
  buffer: array [0..127] of AnsiChar;
  i: Integer;
  GInitData: TWSAData;
begin
  WSAStartup(MakeWord(1, 1), GInitData);
  Result := '';
  PcName := '';

  GetHostName(buffer);

  PH := GetHostByName(buffer);
  if PH = nil then Exit;
  PcName := AnsiString(PH^.h_name);
  pPtr := PaPInAddr(PH^.h_addr_list);
  i := 0;
  while pPtr^[i] <> nil do begin
    Result := inet_ntoa(pPtr^[i]^);
    Inc(i);
  end;
  WSACleanup;
end;
// 自PCのIPアドレスとPC名を得る
procedure TForm1.Button1Click(Sender: TObject);
var
  Ip : AnsiString;
  PcName : AnsiString;
begin
  Edit1.Text := '';
  Edit2.Text := '';

  Ip := LocalIP(PcName);
  if Ip <> '' then begin
    Edit1.Text := string(Ip);
    Edit2.Text := string(PcName);
  end;
end;

procedure TForm1.Button2Click(Sender: TObject);
var
  i : integer;
  n : integer;
  IpHead : Ansistring;
  Ip : Ansistring;
begin
  if Button2.Caption = 'PING' then begin
    runFlag := True;
    Button2.Caption := 'Break';

    Memo1.Lines.Clear;
    IpHead := '192.168.0.';
    n := LastDelimiter('.', Edit1.Text);
    if n > 0 then
      IpHead := AnsiString(Copy(String(Edit1.Text), 1, n));

    for i := 0 to 255 do begin
      if runFlag then begin

        Application.ProcessMessages;

        IP := IpHead + AnsiString(IntToStr(i));
        Label1.Caption := String(IP);
        Label1.Refresh;

        if PingIp(Ip) then
          Memo1.Lines.Add(String(Ip + AnsiString(StringOfChar(' ', 16 - Length(ip)))
             + GetHostName(Ip)));
      end
      else
        Break;
    end;
    if runFlag then
      Memo1.Lines.Add('---- term ----')
    else
      Memo1.Lines.Add('---- break ----');
  end
  else begin
    runFlag := False;
    Button2.Caption := 'PING';
    Application.ProcessMessages;
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  Button1.Caption := 'LocalIP';
  Button2.Caption := 'PING';
  Edit1.Text := '';
  Edit2.Text := '';
  Label1.Caption := '';
  Memo1.Lines.Clear;
end;

end.