Home > Delphi, Networking, WMI > Making a PING with Delphi and the WMI

Making a PING with Delphi and the WMI

Typically we use the IcmpSendEcho function or a component like TIdIcmpClient to make a ping from delphi, today i will show you a third way to do this using the WMI (Windows Management Instrumentation).

The wmi class which allow you to make a ping request is Win32_PingStatus, to use this class you only need to pass the parameter Address value in your WQL sentence , the form of the Address parameter can be either the computer name (ACCOUNT-PC), IPv4 address (192.168.154.102), or IPv6 address (2010:836B:4179::836B:4179).

SELECT * FROM Win32_PingStatus where Address='www.google.com'

some of the advantages of use this class to make a ping is which supports IPv4 addresses and IPv6 addresses (Starting with Windows Vista) , and you can set the ping parameters in a single WQL sentence.

for example if you wanna send a Buffer of 64 bytes (instead of the 32 default size) and resolve the address of the host server you only need to write a sentence like this :

SELECT * FROM Win32_PingStatus where Address='192.168.1.221' AND BufferSize=64 AND ResolveAddressNames=TRUE

Now check this sample console application.

program WMIPing;

{$APPTYPE CONSOLE}

uses
  SysUtils,
  ActiveX,
  ComObj,
  Variants;

function GetStatusCodeStr(statusCode:integer) : string;
begin
  case statusCode of
    0     : Result:='Success';
    11001 : Result:='Buffer Too Small';
    11002 : Result:='Destination Net Unreachable';
    11003 : Result:='Destination Host Unreachable';
    11004 : Result:='Destination Protocol Unreachable';
    11005 : Result:='Destination Port Unreachable';
    11006 : Result:='No Resources';
    11007 : Result:='Bad Option';
    11008 : Result:='Hardware Error';
    11009 : Result:='Packet Too Big';
    11010 : Result:='Request Timed Out';
    11011 : Result:='Bad Request';
    11012 : Result:='Bad Route';
    11013 : Result:='TimeToLive Expired Transit';
    11014 : Result:='TimeToLive Expired Reassembly';
    11015 : Result:='Parameter Problem';
    11016 : Result:='Source Quench';
    11017 : Result:='Option Too Big';
    11018 : Result:='Bad Destination';
    11032 : Result:='Negotiating IPSEC';
    11050 : Result:='General Failure'
    else
    result:='Unknow';
  end;
end;


//The form of the Address parameter can be either the computer name (wxyz1234), IPv4 address (192.168.177.124), or IPv6 address (2010:836B:4179::836B:4179).
procedure  Ping(const Address:string;Retries,BufferSize:Word);
var
  FSWbemLocator : OLEVariant;
  FWMIService   : OLEVariant;
  FWbemObjectSet: OLEVariant;
  FWbemObject   : OLEVariant;
  oEnum         : IEnumvariant;
  iValue        : LongWord;
  i             : Integer;

  PacketsReceived : Integer;
  Minimum         : Integer;
  Maximum         : Integer;
  Average         : Integer;
begin;
  PacketsReceived:=0;
  Minimum        :=0;
  Maximum        :=0;
  Average        :=0;
  Writeln('');
  Writeln(Format('Pinging %s with %d bytes of data:',[Address,BufferSize]));
  FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
  FWMIService   := FSWbemLocator.ConnectServer('localhost', 'root\CIMV2', '', '');
  //FWMIService   := FSWbemLocator.ConnectServer('192.168.52.130', 'root\CIMV2', 'user', 'password');
  for i := 0 to Retries-1 do
  begin
    FWbemObjectSet:= FWMIService.ExecQuery(Format('SELECT * FROM Win32_PingStatus where Address=%s AND BufferSize=%d',[QuotedStr(Address),BufferSize]),'WQL',0);
    oEnum         := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
    if oEnum.Next(1, FWbemObject, iValue) = 0 then
    begin
      if FWbemObject.StatusCode=0 then
      begin
        if FWbemObject.ResponseTime>0 then
          Writeln(Format('Reply from %s: bytes=%s time=%sms TTL=%s',[FWbemObject.ProtocolAddress,FWbemObject.ReplySize,FWbemObject.ResponseTime,FWbemObject.TimeToLive]))
        else
          Writeln(Format('Reply from %s: bytes=%s time=<1ms TTL=%s',[FWbemObject.ProtocolAddress,FWbemObject.ReplySize,FWbemObject.TimeToLive]));

        Inc(PacketsReceived);

        if FWbemObject.ResponseTime>Maximum then
        Maximum:=FWbemObject.ResponseTime;

        if Minimum=0 then
        Minimum:=Maximum;

        if FWbemObject.ResponseTime<Minimum then
        Minimum:=FWbemObject.ResponseTime;

        Average:=Average+FWbemObject.ResponseTime;
      end
      else
      if not VarIsNull(FWbemObject.StatusCode) then
        Writeln(Format('Reply from %s: %s',[FWbemObject.ProtocolAddress,GetStatusCodeStr(FWbemObject.StatusCode)]))
      else
        Writeln(Format('Reply from %s: %s',[Address,'Error processing request']));
    end;
    FWbemObject:=Unassigned;
    FWbemObjectSet:=Unassigned;
    //Sleep(500);
  end;

  Writeln('');
  Writeln(Format('Ping statistics for %s:',[Address]));
  Writeln(Format('    Packets: Sent = %d, Received = %d, Lost = %d (%d%% loss),',[Retries,PacketsReceived,Retries-PacketsReceived,Round((Retries-PacketsReceived)*100/Retries)]));
  if PacketsReceived>0 then
  begin
   Writeln('Approximate round trip times in milli-seconds:');
   Writeln(Format('    Minimum = %dms, Maximum = %dms, Average = %dms',[Minimum,Maximum,Round(Average/PacketsReceived)]));
  end;
end;


begin
 try
    CoInitialize(nil);
    try
      //Ping('192.168.52.130',4,32);
      Ping('theroadtodelphi.wordpress.com',4,32);
    finally
      CoUninitialize;
    end;
 except
    on E:Exception do
        Writeln(E.Classname, ':', E.Message);
 end;
 Readln;
end.

and the output

Categories: Delphi, Networking, WMI
  1. February 2, 2011 at 8:48 am | #1

    Nice post, but the code has broken lines.
    Please don’t use tags, use tags, like this :

     if FWbemObject.ResponseTime>Maximum then
            Maximum:=FWbemObject.ResponseTime;
    
    

    .

    Thanks.

    Thanks.

    • February 2, 2011 at 2:37 pm | #2

      WanC , which browser are you using? the code looks good in Firefox and IE Explorer.

  2. Radu
    February 2, 2011 at 9:07 am | #3

    Hi Rodrigo,

    As usual exceptional examples with very useful information! On this example I could suggest you to change
    “FWMIService := FSWbemLocator.ConnectServer(‘localhost’, ‘root\CIMV2′, ”, ”);” with
    ” FWMIService := FSWbemLocator.ConnectServer(”, ”, ”, ”);”
    due to fact that SWbemLocator.ConnectServer method takes by default the system parameters, if you don’t want to put them explicit. And you have several comments there, even an IP adress :)

    Please keep up the good work, it’s always interesting to read your blog!

    Best regards,
    Radu

    • February 2, 2011 at 2:41 pm | #4

      Radu, thanks for your comments, about your suggestion is always recommendable pass the namespace and the machine name when you use the ConnectServer function. about the commented line is just for illustrate which you can make a ping from a remote machine using the WMI.

  3. Domingo
    February 2, 2011 at 10:03 am | #5

    Muy bueno el código !!!

    Gracias

  4. Rafael Colucci
    April 5, 2011 at 10:53 am | #7

    Hello

    There is a problem with your code. If you try to ping a invalid address like ‘aaaa’ you get this error message:

    Project WMIPing.exe raised exception class EVariantTypeCastError with message ‘Could not convert variant of type (Null) into type (Integer).

    To reproduce this error, simple change:

    Ping(‘theroadtodelphi.wordpress.com’,4,32);

    for

    Ping(‘aaaaaa’,4,32);

    in this case, FWbemObject.StatusCode is getting NULL instead of the error code.

    • April 5, 2011 at 11:17 am | #8

      Rafael the problem is due (as you say) which the StatusCode property return a null value which cannot be translated to a valid status message, the code was modified to handle this issue. try now and let me know the results of your tests.

      • Rafael Colucci
        April 5, 2011 at 12:39 pm | #9

        OK .. the problem is gone now (i had already did what you just did). But it seems to me that the Status code is always null when an address is invalid. This way, you will never get the error status when you use GetStatusCodeStr. Every invalid address i have tried gets a null status code.

        • April 5, 2011 at 12:56 pm | #10

          Rafael. try checking the value of the PrimaryAddressResolutionStatus property this value always return a valid code (not null) even if the address passed is invalid, you can translate the value to an string using the GetStatusCodeStr function.

          • Rafael Colucci
            April 5, 2011 at 1:10 pm | #11

            OK. Now it works perfect. You should consider changing your source code also.
            Thanks for you help and good job btw.

          • April 5, 2011 at 1:15 pm | #12

            ok, no problem, glad to help you.

  5. EMB
    August 29, 2011 at 3:01 pm | #13

    Just had to use this today. (:
    Gold as always.
    Do you know any drawback of using this comparing to usual IcmpSendEcho approach?
    thanks!

    EMB

    • August 29, 2011 at 3:48 pm | #14

      There is not drawbacks, you can get the same results using the IcmpSendEcho function or the Win32_PingStatus wmi class.

      • EMB
        August 30, 2011 at 10:40 am | #15

        Thanks! (:
        the problem with IcmpSendEcho is that we should not statically link to the library. Instead, call LoadLibrary and then GetProccess, and if fails, try again.
        Sometimes, I just wanna a simpler code that work in all target windows…

  1. February 2, 2011 at 1:02 am | #1
  2. October 30, 2011 at 4:18 pm | #2

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 61 other followers