Question

InternetGetConnectedState(@flags, 0) doesn't work

Asked by: Delphiwizard

Hi,

When I try to check if my PC is connected to the internet, than this function doesn't work with my configuration.
 
   If InternetGetConnectedState(@flags, 0) then
   begin
      // Only do this if connected.
   end;

My PC is connected like this

 PC -> Router -> ADSL modem.

When I'm online everything works fine. But when I shut down my ADSL-modem it still thinks I'm online.
How can I check if there is REALY a connection present?

Thanks, Stef

This Question has been solved and asker verified All Experts Exchange premium technology solutions are available to subscription members.

Subscribe now for full access to Experts Exchange and get

Instant Access to this Solution

  • Plus...
  • 30 Day FREE access, no risk, no obligation
  • Collaborate with the world's top tech experts
  • Unlimited access to our exclusive solution database
  • Never be left without tech help again

Subscribe Now

Asked On
2004-12-12 at 10:01:09ID21239624
Tags

internetgetconnectedstate

Topic

Delphi Programming

Participating Experts
4
Points
500
Comments
21

Trusted by hundreds of thousands everyday for fast, accurate and reliable tech support.

  • "The time we save is the biggest benefit of Experts Exchange to Warner Bros. What could take multiple guys 2 hours or more each to find is accessed in around 15 minutes on Experts Exchange." Mike Kapnisakis, Warner Bros.
  • "Our team likes having a resource that is more secure than just using Google and most experts using this service really know their stuff. It's nice to look here first versus using Google." Dayna Sellner, Lockheed Martin
  • "Anytime that I've been stumped with a problem, 9 out of 10 times Experts Exchange has either the accepted solution or an open discussion of the potential solution to the problem." Kenny Red, eBay Inc.

See what Experts Exchange can do for you.

Got a question?

We've got the answer.

Experts Exchange has been collecting answers to technology questions since 1996…3 million and counting! If you have a question, chances are we already have your answer.

Screenshot of Experts Exchange Knowledgebase

Need individual assistance?

Our experts are ready to help.

If you can't find the exact answer you're looking for, ask our exclusive community of 50,000 experts. You’ll get a personalized answer from a trusted professional.

Screenshot of Experts Exchange Knowledgebase

Want to learn from the best?

Read articles from industry experts.

Thousands of free tech tips, tricks, how-to’s and tutorials are available in our peer reviewed articles section. See for yourself how smart our experts are, no login required.

Screenshot of an Article

Working on a long term project?

Store your work and research.

Save solutions to your questions, answers you’ve discovered through searching plus helpful articles in your personal knowledgebase for easy future access.

Screenshot of Experts Exchange Knowledgebase

Access the answers to your technology questions today.

Subscribe Now

30-day free trial. Register in 60 seconds.

What Makes Experts Exchange Unique?

Members of the expert community talk about why the experience at Experts Exchange is different than what you will find anywhere else.

Trusted by the world's most respected brands.

image of each brand's logo

Faithfully serving IT professionals since 1996.

Experts Exchange Logo

Try it out and discover for yourself.

Subscribe Now

30-day free trial. Register in 60 seconds.

Related Solutions

  1. adsl. routers modems and linux....
    I'm about to get adsl installed in my flat - shared with 6 mates. We all have computers and wish to use the adsl at the same time. I am getting a static ip, so ideally i would like to setup up a software firewall on a linux box i have just built - with redhat 6. (i.e. i want ...
  2. Sonicwall behind ADSL Modem/Router
    Can a Sonicwall SOHO3 be configured behind a Netgear DG814 ADSL Modem/Router. If so, how is is supposed to be configured? Any comments welcome!
  3. ADSL modem
    Hi, I'm a novice for Linux and have installed Red Hat 9. The problem is now how to connect to internet with my ADSL modem... I already find out that my modem was not capable of working with Linux. I'm looking for a new solution... Question : What is the (1) best + cheapest,...
  4. Using router in conjunction with ADSL modem - USB input
    I just got an ADSL modem. Previously when I used ADSL modems they have standard patch cable output, but this one only has usb output. I want to use a router to share the connection. Is this possible in hardware terms? Are there any routers which take USB input to their WAN po...

Free Tech Articles

  1. WARNING: 5 Reasons why you should NEVER fix a computer for free.
    It is in our nature to love the puzzle. We are obsessed. The lot of us. We love puzzles. We love the challenge. We thrive on finding the answer. We hate disarray. It bothers us deep in our soul. W...
  2. SCCM OSD Basic troubleshooting
    SCCM 2007 OSD is a fantastic way to deploy operating systems, however, like most things SCCM issues can sometimes be difficult to resolve due to the sheer volume of logs to sift through and the dispe...
  3. Migrate Small Business Server 2003 to Exchange 2010 and Windows 2008 R2
    This guide is intended to provide step by step instructions on how to migrate from Small Business Server 2003 to Windows 2008 R2 with Exchange 2010. For this migration to work you will need the fo...
  4. Create a Win7 Gadget
    This article shows you how to create a simple "Gadget" -- a sort of mini-application supported by Windows 7 and Vista. Gadgets can be dropped anywhere on the desktop to provide instant information, ...
  5. Outlook continually prompting for username and password
    There have been a lot of questions recently regarding Outlook prompting for a username and password whilst using Exchange 2007. There are a few reasons why this would happen and I will try to cover t...
  6. Backup Exchange 2010 Information Store using Windows Backup
    There seems to be quite a lot of confusion around the ability to backup Exchange 2010 using the built in Windows Backup feature. This stems from the omission of this feature prior to Exchange 2007 s...

Cloud Class Webinars

  1. Avoiding Bugs in Microsoft Access
    Alison Balter takes and in-depth look at avoiding bugs in Access. In this webinar you will learn about using the immediate window to debug your applications, invoking the debugger, using breakpoints to troubleshoot, stepping through code, setting the next statement to execute, ...
  2. Top 10 Best New Features in Visio 2010
    Scott Helmers gives live demonstrations of the top 10 new features in Visio 2010. This webinar will teach you how to create compelling diagrams by adding shapes to the page with a single click, linking the shapes in a diagram to data in Excel (or SQL Server, or SharePoint), ...
  3. IT Consultant Business Secrets Revealed
    Michael Munger, Experts Exchange tech pro and IT consultant, pulls back the curtain on his very successful businesses and answers question on every IT consultant and business owner should know about. He shares secrets on what he did to solve the 5 most common problems in IT, ...
  4. Disaster Recovery and Business Continuity
    Quest CTO, Mike Billon, gives an overview of the steps involved in building a dunamic disaster recovery plan. Through case studies and an examination of software/hardware tooles for monitoring and testing, you'll gain a better understandin of where you are, where you want ...
  5. Organize Your Visio Diagrams with Containers and Lists
    Scott Helmers uses cross functional flowcharts, wireframe diagrams, data graphic legends and seating charts to teach you: how to ustilize all three new structured diagram components in Visio 2010, the best practices for organizeing shapes in previous version of Visio, how to organize ...
  6. How to Us Objects, Properties, Events and Methods in Microsoft Access
    Alison Dalter gives an in-depbth look at objects, properties, events and methods in Microsoft Access. In this webinar you will learn about using the object browser, referring to objects, working with properties and methods, working with object variables, understanding the ...

Join the Community

Give a Little. Get a Lot.

Join the community of experts here and help other tech pros by answering question in your area of expertise. You can earn FREE access to all Experts Exchange's premium features and resources.

Join the Community

Answers

 

by: Ivanov_GPosted on 2004-12-12 at 12:40:42ID: 12805078

try to ping some address in internet, or better your ISP servers (gateway or DNS) since it will be much faster. Send 3 pings and if 1 returns - you are online :)

 

by: DelphiwizardPosted on 2004-12-12 at 13:59:16ID: 12805320

How can I do that from within Delphi?
Can you give an example?

 

by: thousandjulysPosted on 2004-12-12 at 17:54:12ID: 12806070

try the InetIsOffline API

function InetIsOffline(Flag: Integer): Boolean; stdcall; external 'URL.DLL';

returns true if the computer is offline.

 

by: rllibbyPosted on 2004-12-12 at 18:42:59ID: 12806223

There is also a way using the sens api library set. Please see the TNetwork class that I put together for the  following  q: http://www.experts-exchange.com/Programming/Programming_Languages/Delphi/Q_21149551.html

Regards,
Russell

 

by: DelphiwizardPosted on 2004-12-12 at 23:16:34ID: 12806931

Answer to: thousandjulys
InetIsOffline always returns False. So this isn't useful in my case.


Answer to: Rlibby
I've Added unit Network to my project and also download the IPHelper from Jedi.
But how do I use them?
1. To determine if there is a connection active
2. To determine the connectiontype (modem, lan)
Can you supply twee buttonclick-events that show usage?

Thank you very much.
Stef

 

by: Ivanov_GPosted on 2004-12-13 at 01:28:14ID: 12807324

> How can I do that from within Delphi?
> Can you give an example?

Ping without raw sockets
http://www.delphipages.com/news/detaildocs.cfm?ID=93

TPing component
http://www.torry.net/vcl/internet/other/icmp.zip

 

by: DaFoxPosted on 2004-12-13 at 03:53:41ID: 12808074

Hi,

try these functions:

const
  NETWORK_ALIVE_LAN = $00000001;
  NETWORK_ALIVE_WAN = $00000002;
  NETWORK_ALIVE_AOL = $00000004;

function IsNetworkAlive(out Flags: DWORD): BOOL; stdcall;
  external 'sensapi.dll' name 'IsNetworkAlive';

function IsDestinationReachable(Destination: PChar; out QOCInfo: TQOCInfo): BOOL; stdcall;
  external 'sensapi.dll' name 'IsDestinationReachableA';

Regards,
Markus

 

by: rllibbyPosted on 2004-12-13 at 07:50:08ID: 12810139


As Markus stated above, the 2 SENS apis (actually, only need one) can be used to determine network connectivity. These are the same functions that my network class uses to determine connectivity and if a site can be reached or not. So, all that is needed to accomplish the 2 requirements:

1.) Determine if connected
2.) If connected, determine connection type

Is this:

var  dwFlags:       DWORD;
begin

  // Determine the current connections
  if IsNetworkAlive(dwFlags) then
  begin
     // Set connection types
     if ((dwFlags and NETWORK_ALIVE_LAN) = NETWORK_ALIVE_LAN) then
        // Connected via lan
        ShowMessage('Connected via LAN')
     else
        // Connected via lan (or for win 95/98 connected to AOL via ras)
        ShowMessage('Connected via Modem');
  end
  else
     ShowMessage('Not connected!');

end;

---------------

Regards,
Russell

 

by: DaFoxPosted on 2004-12-13 at 08:04:46ID: 12810340

>> As Markus stated above, the 2 SENS apis (actually, only need one) can be used to determine network connectivity.
>> These are the same functions that my network class uses to determine connectivity and if a site can be reached or not.

Sorry, I didn't follow your link above and so didn't know that you already put all of this together in a component. BTW, my own component almost looks the same. ;-)

Regards,
Markus

 

by: DelphiwizardPosted on 2004-12-13 at 10:40:41ID: 12811852

Rlibby: When running last example
Delphi comes up with the message "Incompatible types Cardinal and PDword"

Regards, Stef

 

by: rllibbyPosted on 2004-12-13 at 10:48:46ID: 12811916


Sorry, should have indicated that the example code I gave was based off from Markus's declaration above. If using my declaration (which was taken from the MSDN) then just preface dwFlags with the @ sign

eg

  if IsNetworkAlive(@dwFlags) then
  begin
     // Set connection types
     if ((dwFlags and NETWORK_ALIVE_LAN) = NETWORK_ALIVE_LAN) then
        // Connected via lan
        ShowMessage('Connected via LAN')


Only difference is my declaration allows the passing of nil, and the other declaration always requires a dword variable to be passed.

Russell

 

by: DelphiwizardPosted on 2004-12-13 at 11:01:40ID: 12812009

Thanks, the project works..... BUT
It still thinks I am connected to the internet although I'm only connected to my own network.
Probably this function is only checking if there is a connection to an IP-adres, where it should scan all IP's for the local computer and if an IP is detected and this IP is not in the list of the local networkcard then we have an internet connection.

I found a component that will check for just that, but that component can't detect Cable-modemconnections.
Maybe one of you can combine these two.

Here is the code of the component - Thanks to Mark Gauthier

====================
unit INetDetect;

interface

uses
  Windows, Messages, Classes, Forms, Winsock, ExtCtrls;

type
  TAddrItem = class(TCollectionItem)
  public
   s: string;
  end;

  TINetDetect = class(TComponent)
  private
    FLocalAddrs: TCollection;
    FCurrentIP: String;
    FHostName: PChar;
    FOnline: Boolean;
    FEnabled: Boolean;
    FDispatchInterval: Cardinal;
    FOnChanged: TNotifyEvent;
    Timer: TTimer;
    function  Get(Index: Integer): string;
    function  GetCount: Integer;
    procedure GetLocalIPs;
    procedure SetEnabled(Value: Boolean);
    procedure SetDispatchInterval(Value: Cardinal);
    procedure OnTimer(Sender: TObject);
    procedure DoNothingBool(b: boolean);
    procedure DoNothingString(s: string);
    function  GetFHostName: string;
  protected
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    property LocalIPs[Index: Integer]: string read Get;
    property LocalIPsCount: integer read GetCount;
  published
    property Enabled: Boolean read FEnabled write SetEnabled;
    property DispatchInterval: Cardinal read FDispatchInterval write SetDispatchInterval;
    property Online: Boolean read FOnline write DoNothingBool;
    property CurrentIP : String read FCurrentIP write DoNothingString;
    property OnChanged: TNotifyEvent read FOnChanged write FOnChanged;
    property HostName: String read GetFHostName write DoNothingString;
  end;

//{$EXTERNALSYM WSAIoctl}
function WSAIoctl( hSocket: TSocket; ControlCode:dword;
                   InBuf : Pointer; InBufLen:DWord;
                   OutBuf : Pointer; OutBufLen:DWord;
                   BytesReturned : PDWord;
                   lpOverlapped: POverlapped;
                   lpOverlappedRoutine:pointer) : Integer; stdcall;
//{$EXTERNALSYM WSASocket}
function WSASocket(Family, sType, Protocol : Integer;
                   lpProtocolInfo : Pointer;
                   Group : uint;
                   dwFlags : DWORD): TSocket; stdcall;

function WSAIoctl;          external     'ws2_32.dll' name 'WSAIoctl';
function WSASocket;         external     'ws2_32.dll' name 'WSASocketA';


Type

  _INTERFACE_INFO = record
    iiFlags            : ulong;      //* Type and status of the interface */
    iiAddress          : TSockaddr;  //* Interface address */
    iiBroadcastAddress : TSockaddr;  //* Broadcast address */
    iiNetmask          : TSockaddr;  //* Network mask */
  end;

Const
 IFF_UP =            $00000001; //* Interface is up */
 IFF_BROADCAST =      $00000002; //* Broadcast is  supported */
 IFF_LOOPBACK =       $00000004; //* this is loopback interface */
 IFF_POINTTOPOINT =     $00000008; //*this is point-to-point interface*/
 IFF_MULTICAST =      $00000010; //* multicast is supported */



procedure Register;

implementation

uses sysutils;

procedure TINetDetect.DoNothingString(s: string); begin {} end;

procedure TINetDetect.DoNothingBool(b: boolean); begin {} end;

function  TINetDetect.GetFHostName: string;
begin
     Result := StrPas(FHostName);
end;

constructor TINetDetect.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FEnabled := False;
  FDispatchInterval := 1000;

  Getmem(FHostName, 64);
  FLocalAddrs := TCollection.Create(TAddrItem);

  Timer := TTimer.Create(self);
  Timer.Enabled := FEnabled;
  Timer.interval := FDispatchInterval;
  Timer.OnTimer := OnTimer;

  GetLocalIPs;
  OnTimer(Self); // Get current status
end;

destructor TINetDetect.Destroy;
begin
  FLocalAddrs.Clear;
  FLocalAddrs.Free;
  Timer.Free;
  FreeMem(FHostName);

  FEnabled := False;
  inherited Destroy;
end;

procedure TINetDetect.GetLocalIPs;
  const SIO_GET_INTERFACE_LIST : dword = 1074033791;
var
    pAddrInet : TSockAddr;
    OutBufLen,
    RecvBytes,
    i         : DWORD;
    wsError   : Integer;
    WSAData   : TWSAData;
    MySocket  : TSocket;
    localAddr : Array[1..10] of _INTERFACE_INFO; //up to 10 NICs
begin
  wsError := Winsock.WSAStartup(2,  WSAData); //winsock 2 or better.
  If wsError <> 0 then  exit;

  Gethostname(FHostName, 64);
  MySocket := WSASocket(AF_INET, Sock_DGRAM, IPPROTO_UDP, nil,0,0);
  If MySocket = INVALID_SOCKET then exit;
  OutBufLen := Sizeof(localAddr);
  RecvBytes := OutBufLen;
  FillChar(LocalAddr,OutBufLen,0);
  wsError := WSAIoctl(MySocket,SIO_GET_INTERFACE_LIST,nil,0,@localAddr,OutBufLen,@RecvBytes,nil,nil);
  if wsError = SOCKET_ERROR then
  begin
    wsError := WSAGetLastError;
    Raise Exception('Socket error:'+IntToStr(wsError));
    exit;
  end;
  for i := 1 to RecvBytes div Sizeof(_Interface_Info) do
  begin
      pAddrInet := localAddr[i].iiAddress;
      With FLocalAddrs.Add as TAddrItem do s:=inet_ntoa(pAddrInet.sin_addr );
  end;
  closesocket(MySocket);
  WSACleanup();
end;


procedure TINetDetect.OnTimer(Sender: TObject);
type
  TaPInAddr = Array[0..10] of PInAddr;
  PaPInAddr = ^TaPInAddr;
var
  phe: PHostEnt;
  pptr: PaPInAddr;
  I,J: Integer;
  GInitData: TWSAData;
  NewStatus,
  OldStatus : Boolean;
  NewIP: string;
  IP: string;
  Found: Boolean;
begin
  Timer.Enabled := false;
  WSAStartup($101, GInitData);
  GetHostName(FHostName, 64);
  phe := GetHostByName(FHostName);
  if phe = nil then Exit;
  pPtr := PaPInAddr(phe^.h_addr_list);
  I := 0;

  NewIP := '';
  NewStatus := False;
  OldStatus := FOnline;

  while pPtr^[I] <> nil do
   begin
    IP := inet_ntoa(pptr^[I]^);
    Found := false;
    For j := 0 to LocalIPsCount-1 do
    begin
      If (FLocalAddrs.Items[j] as TAddrItem).s = IP then
      begin
           Found := true;
           Break; { Break for }
      end;
    end;
    If Not Found then
    begin
         // If IP is a new Address where are connected...
           NewStatus := true;
           NewIP := IP;
           Break; { break while }
    end;
    Inc(I);
   end;

  WSACleanup;

  FCurrentIP := NewIP;
  If NewStatus <> OldStatus then
  begin
       FOnline := NewStatus;
       if Assigned(FOnChanged) then FOnChanged(self);
  end;

  Timer.Enabled := true;
end;

procedure TINetDetect.SetEnabled(Value: Boolean);
begin
  if Value <> FEnabled then
   begin
    FEnabled := Value;
    Timer.Enabled := Value;
   end;
end;

procedure TINetDetect.SetDispatchInterval(Value: Cardinal);
begin
  if Value <> FDispatchInterval then
   begin
    FDispatchInterval := Value;
    Timer.Interval := Value;
   end;
end;


function TINetDetect.Get(Index: Integer): string;
begin
     If (FLocalAddrs.Count > 0) and (Index In[0..FLocalAddrs.Count]) then
        Result := (FLocalAddrs.Items[Index] as TAddrItem).S ;
end;

function  TINetDetect.GetCount: Integer;
begin
     Result := FLocalAddrs.Count;
end;

procedure Register;
begin
  RegisterComponents('Internet', [TINetDetect]);
end;

end.

 

by: rllibbyPosted on 2004-12-13 at 11:18:39ID: 12812149


It would be much simpler to use the IsDestinationReachable (which can also provide a much better test)

type
  tagQOCINFO        =  packed record
     dwSize:        DWORD;
     dwFlags:       DWORD;
     dwInSpeed:     DWORD;
     dwOutSpeed:    DWORD;
  end;
  QOCINFO           =  tagQOCINFO;
  TQOCInfo          =  QOCINFO;
  PQOCInfo          =  ^TQOCInfo;

function IsDestinationReachable(lpszDestination: PChar; lpQOCInfo: PQOCInfo): BOOL; stdcall; external 'sensapi.dll' name 'IsDestinationReachableA';

usage:

var  qocData:       TQOCInfo;
begin

  // Set the size for quality of connection structure
  qocData.dwSize:=SizeOf(TQOCInfo);

  // Check to see if destination can be reached
  if IsDestinationReachable('www.google.com', @qocData) then
  begin
     // Destination can be reached
     ShowMessage('Destination reachable');
  end;

end;

----

Russell


 

by: DelphiwizardPosted on 2004-12-13 at 11:31:34ID: 12812259

Almost, we are getting there.
When the destination is reachable it works nice and fast.
But when I shutdown my ADSL-modem it takes forever (I did program reset after a few minutes).
Checking of the IP-addresses however is very quick.

Regards, Stef

 

by: DelphiwizardPosted on 2004-12-13 at 12:51:18ID: 12812969

Is someone considering combining the Rlibby unit with the Component?
I would do it myself if I could :-)

Thanks Stef

 

by: rllibbyPosted on 2004-12-14 at 07:33:46ID: 12820264

Stef,

The component you listed above does not work; at least not for MANY configurations. For example, when connected to the internet and I start my program that uses the component code. The following happens:

Two IP addresses are listed for the 2 interfaces (this is expected)
--------------------------------------------
10.xx.xx.xx      - My network ip address
0.0.0.0       - My loopback address

The gethostbyname call returns a PHostEnt pointer, and in it exists one IP address, which is the 10.xx.xx.xx from above. According to the component I am "offline", but in actuality I AM online. When I unplug my network cable, the IP address for the gethostbyname call reverts to a local address of 127.0.0.1. And at that point, the component now believes that I am online; why? because the 127.0.0.1 address does not exist in the interface IP address list. So for me, the component states exactly the OPPOSITE from my actual state.

Simply put, you are running into something that many of us have run in to. And that is, the difficulties involved with determining if a computer has network access to a remote destination (the internet). So, while there may be a number of different api calls, from a number of different libraries, only one thing is guaranteed: none of them can tell you 100%, without a doubt, that you are connected or not without actually attempting to reach the destination in question. As you have also found out, attempting to reach a destination when the communication channel is down can also be a lengthy process...(but one that could be resolved with the use of threads).

Regarding the conversion of the component (to a single line function); I considered it.... but have no plans on spending time converting something that does not work to start with.


Regards,
Russell

 

by: DelphiwizardPosted on 2004-12-14 at 13:35:38ID: 12824374

Maybe this would work (if it can be done).

Determine all installed hardware that is able to connect beyond the computer itself.
These are Networkcards and Modems (maybe Firewire 1394 and others?)

I assume that it is possible to gather all IP-addresses related to these hardware components.
Make a internal list of these IP's.

Check all IP's that are currently accessable.
If one of them isn't in the list of local IP's then I presume a connection is available with the internet (beyond the own local netwerk).

Regards, Stef

 

by: rllibbyPosted on 2004-12-14 at 16:02:27ID: 12825659

Stef,

What you describe above is not only difficult to achieve, but it also follows the same flawed logic as the component code you posted. It can only tell you about the next hop in your network configuration. For a computer connected to a local LAN system, then this will either be the router or dhcp server. It tells you absolutely nothing about your connection (or lack of) to an external network.

Anyways, I would like to finish this question up, and also have you satisfied with the results. You, on the same hand, should be willing to accept a small (3-5) second delay in the checking of the network when the internet connection is disabled or not connected.

So, in order to achieve this, I will work on converting some code over that performs icmp pinging. This should provide the results you are after, is very realiable, and can be set to timeout at a user defined time interval. While I am doing this, I wonder if you could check the following:

Replace the "www.google.com" param from the IsDestinationReachable(...) call, and test again with the cable modem turned off.

Regards,
Russell

 

by: rllibbyPosted on 2004-12-14 at 16:13:20ID: 12825715

I meant, replace it with....

64.233.167.99  // One of google's ip's

Russell


 

by: rllibbyPosted on 2004-12-14 at 16:40:01ID: 12825851


Thought I was going to have to convert some C code over, but was pleasantly suprised to find that Franois had already translated the icmp code over to delphi.

Hopefull, this should work as well for you as it did for me....

function IsInternetConnected(Timeout: Integer): Boolean;
var  icmpTest:      TICMP;
begin

  // Create icmp wrapper
  icmpTest:=TICMP.Create;

  // Resource protection
  try
     // Set timeout and destination address. This could also be enhanced as mentioned by Ivanov_g where
     // you send out one request to multiple destinations, and just check to make sure that  at least one replied.
     // This would help to avoid the rare situautions when a site was down/unreachable, but you are connected.
     icmpTest.Address:='64.233.167.104';
     icmpTest.Timeout:=Timeout;
     // Ping the destination
     result:=(icmpTest.Ping > 0);
  finally
     // Free object
     icmpTest.Free;
  end;

end;

// To test the code - I used 1 second which is a pretty safe value.
  if IsInternetConnected(1000) then
     ShowMessage('Connected...')
  else
     ShowMessage('Not connected...');


Russell

-----

And the icmp code:

{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

Author:       Franois PIETTE
Description:  This unit encapsulate the ICMP.DLL into an object of type TICMP.
              Using this object, you can easily ping any host on your network.
              Works only in 32 bits mode (no Delphi 1) under NT or 95.
              TICMP is perfect for a console mode program, but if you build a
              GUI program, you could use the TPing object wich is a true VCL
              encapsulating the TICMP object. Then you can use object inspector
              to change properties or event handler. This is much simpler to
              use for a GUI program.
EMail:        http://users.swing.be/francois.piette  francois.piette@swing.be
              http://www.rtfm.be/fpiette             francois.piette@rtfm.be
              francois.piette@pophost.eunet.be
Creation:     January 6, 1997
Version:      1.04
Support:      Use the mailing list twsocket@rtfm.be See website for details.
Legal issues: Copyright (C) 1997-2000 by Franois PIETTE
              Rue de Grady 24, 4053 Embourg, Belgium. Fax: +32-4-365.74.56
              <francois.piette@pophost.eunet.be>

              This software is provided 'as-is', without any express or
              implied warranty.  In no event will the author be held liable
              for any  damages arising from the use of this software.

              Permission is granted to anyone to use this software for any
              purpose, including commercial applications, and to alter it
              and redistribute it freely, subject to the following
              restrictions:

              1. The origin of this software must not be misrepresented,
                 you must not claim that you wrote the original software.
                 If you use this software in a product, an acknowledgment
                 in the product documentation would be appreciated but is
                 not required.

              2. Altered source versions must be plainly marked as such, and
                 must not be misrepresented as being the original software.

              3. This notice may not be removed or altered from any source
                 distribution.

              4. You must register this software by sending a picture postcard
                 to the author. Use a nice stamp and mention your name, street
                 address, EMail address and any comment you like to say.

Updates:
Dec 13, 1997 V1.01 Added OnEchoRequest and OnEchoReply events and removed the
             corresponding OnDisplay event. This require to modify existing
             programs.
Mar 15, 1998 V1.02 Deplaced address resolution just before use
Sep 24, 1998 V1.93 Changed TIPAddr and others to LongInt to avoid range error
             problems with Delphi 4
Jan 24, 1999 V1.11 Surfaced Flags property to allow fragmentation check
             (Flags = IP_FLAG_DF to enable fragmentation check)


 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
unit Icmp;

interface

{$IFDEF VER80}
// This source file is *NOT* compatible with Delphi 1 because it uses
// Win 32 features.
{$ENDIF}

uses
  Windows, SysUtils, Classes, WinSock;

const
  IcmpVersion = 102;
  IcmpDLL     = 'icmp.dll';

  // IP status codes returned to transports and user IOCTLs.
  IP_SUCCESS                  = 0;
  IP_STATUS_BASE              = 11000;
  IP_BUF_TOO_SMALL            = (IP_STATUS_BASE + 1);
  IP_DEST_NET_UNREACHABLE     = (IP_STATUS_BASE + 2);
  IP_DEST_HOST_UNREACHABLE    = (IP_STATUS_BASE + 3);
  IP_DEST_PROT_UNREACHABLE    = (IP_STATUS_BASE + 4);
  IP_DEST_PORT_UNREACHABLE    = (IP_STATUS_BASE + 5);
  IP_NO_RESOURCES             = (IP_STATUS_BASE + 6);
  IP_BAD_OPTION               = (IP_STATUS_BASE + 7);
  IP_HW_ERROR                 = (IP_STATUS_BASE + 8);
  IP_PACKET_TOO_BIG           = (IP_STATUS_BASE + 9);
  IP_REQ_TIMED_OUT            = (IP_STATUS_BASE + 10);
  IP_BAD_REQ                  = (IP_STATUS_BASE + 11);
  IP_BAD_ROUTE                = (IP_STATUS_BASE + 12);
  IP_TTL_EXPIRED_TRANSIT      = (IP_STATUS_BASE + 13);
  IP_TTL_EXPIRED_REASSEM      = (IP_STATUS_BASE + 14);
  IP_PARAM_PROBLEM            = (IP_STATUS_BASE + 15);
  IP_SOURCE_QUENCH            = (IP_STATUS_BASE + 16);
  IP_OPTION_TOO_BIG           = (IP_STATUS_BASE + 17);
  IP_BAD_DESTINATION          = (IP_STATUS_BASE + 18);

  // status codes passed up on status indications.
  IP_ADDR_DELETED             = (IP_STATUS_BASE + 19);
  IP_SPEC_MTU_CHANGE          = (IP_STATUS_BASE + 20);
  IP_MTU_CHANGE               = (IP_STATUS_BASE + 21);

  IP_GENERAL_FAILURE          = (IP_STATUS_BASE + 50);

  MAX_IP_STATUS               = IP_GENERAL_FAILURE;

  IP_PENDING                  = (IP_STATUS_BASE + 255);

  // IP header flags
  IP_FLAG_DF                  = $02;         // Don't fragment this packet.

  // IP Option Types
  IP_OPT_EOL                  = $00;         // End of list option
  IP_OPT_NOP                  = $01;         // No operation
  IP_OPT_SECURITY             = $82;         // Security option.
  IP_OPT_LSRR                 = $83;         // Loose source route.
  IP_OPT_SSRR                 = $89;         // Strict source route.
  IP_OPT_RR                   = $07;         // Record route.
  IP_OPT_TS                   = $44;         // Timestamp.
  IP_OPT_SID                  = $88;         // Stream ID (obsolete)
  MAX_OPT_SIZE                = $40;

type
  // IP types
  TIPAddr   = LongInt;   // An IP address.
  TIPMask   = LongInt;   // An IP subnet mask.
  TIPStatus = LongInt;   // Status code returned from IP APIs.

  PIPOptionInformation = ^TIPOptionInformation;
  TIPOptionInformation = packed record
     TTL:         Byte;      // Time To Live (used for traceroute)
     TOS:         Byte;      // Type Of Service (usually 0)
     Flags:       Byte;      // IP header flags (usually 0)
     OptionsSize: Byte;      // Size of options data (usually 0, max 40)
     OptionsData: PChar;     // Options data buffer
  end;

  PIcmpEchoReply = ^TIcmpEchoReply;
  TIcmpEchoReply = packed record
     Address:       TIPAddr;              // Replying address
     Status:        DWord;                // IP status value
     RTT:           DWord;                // Round Trip Time in milliseconds
     DataSize:      Word;                 // Reply data size
     Reserved:      Word;                 // Reserved
     Data:          Pointer;              // Pointer to reply data buffer
     Options:       TIPOptionInformation; // Reply options
  end;

  // IcmpCreateFile:
  //     Opens a handle on which ICMP Echo Requests can be issued.
  // Arguments:
  //     None.
  // Return Value:
  //     An open file handle or INVALID_HANDLE_VALUE. Extended error information
  //     is available by calling GetLastError().
  TIcmpCreateFile  = function: THandle; stdcall;

  // IcmpCloseHandle:
  //     Closes a handle opened by ICMPOpenFile.
  // Arguments:
  //     IcmpHandle  - The handle to close.
  // Return Value:
  //     TRUE if the handle was closed successfully, otherwise FALSE. Extended
  //     error information is available by calling GetLastError().
  TIcmpCloseHandle = function(IcmpHandle: THandle): Boolean; stdcall;

  // IcmpSendEcho:
  //     Sends an ICMP Echo request and returns one or more replies. The
  //     call returns when the timeout has expired or the reply buffer
  //     is filled.
  // Arguments:
  //     IcmpHandle         - An open handle returned by ICMPCreateFile.
  //     DestinationAddress - The destination of the echo request.
  //     RequestData        - A buffer containing the data to send in the
  //                          request.
  //     RequestSize        - The number of bytes in the request data buffer.
  //     RequestOptions     - Pointer to the IP header options for the request.
  //                          May be NULL.
  //     ReplyBuffer        - A buffer to hold any replies to the request.
  //                          On return, the buffer will contain an array of
  //                          ICMP_ECHO_REPLY structures followed by options
  //                          and data. The buffer should be large enough to
  //                          hold at least one ICMP_ECHO_REPLY structure
  //                          and 8 bytes of data - this is the size of
  //                          an ICMP error message.
  //     ReplySize          - The size in bytes of the reply buffer.
  //     Timeout            - The time in milliseconds to wait for replies.
  // Return Value:
  //     Returns the number of replies received and stored in ReplyBuffer. If
  //     the return value is zero, extended error information is available
  //     via GetLastError().
  TIcmpSendEcho    = function(IcmpHandle:          THandle;
                              DestinationAddress:  TIPAddr;
                              RequestData:         Pointer;
                              RequestSize:         Word;
                              RequestOptions:      PIPOptionInformation;
                              ReplyBuffer:         Pointer;
                              ReplySize:           DWord;
                              Timeout:             DWord
                             ): DWord; stdcall;

  // Event handler type declaration for TICMP.OnDisplay event.
  TICMPDisplay = procedure(Sender: TObject; Msg : String) of object;
  TICMPReply   = procedure(Sender: TObject; Error : Integer) of object;

  // The object wich encapsulate the ICMP.DLL
  TICMP = class(TObject)
  private
    hICMPdll :        HModule;                    // Handle for ICMP.DLL
    IcmpCreateFile :  TIcmpCreateFile;
    IcmpCloseHandle : TIcmpCloseHandle;
    IcmpSendEcho :    TIcmpSendEcho;
    hICMP :           THandle;                    // Handle for the ICMP Calls
    FReply :          TIcmpEchoReply;             // ICMP Echo reply buffer
    FAddress :        String;                     // Address given
    FHostName :       String;                     // Dotted IP of host (output)
    FHostIP :         String;                     // Name of host      (Output)
    FIPAddress :      TIPAddr;                    // Address of host to contact
    FSize :           Integer;                    // Packet size (default to 56)
    FTimeOut :        Integer;                    // Timeout (default to 4000mS)
    FTTL :            Integer;                    // Time To Live (for send)
    FFlags :          Integer;                    // Options flags
    FOnDisplay :      TICMPDisplay;               // Event handler to display
    FOnEchoRequest :  TNotifyEvent;
    FOnEchoReply :    TICMPReply;
    FLastError :      DWORD;                      // After sending ICMP packet
    FAddrResolved :   Boolean;
    procedure ResolveAddr;
  public
    constructor Create; virtual;
    destructor  Destroy; override;
    function    Ping : Integer;
    procedure   SetAddress(Value : String);
    function    GetErrorString : String;

    property Address       : String         read  FAddress   write SetAddress;
    property Size          : Integer        read  FSize      write FSize;
    property Timeout       : Integer        read  FTimeout   write FTimeout;
    property Reply         : TIcmpEchoReply read  FReply;
    property TTL           : Integer        read  FTTL       write FTTL;
    Property Flags         : Integer        read  FFlags     write FFlags;
    property ErrorCode     : DWORD          read  FLastError;
    property ErrorString   : String         read  GetErrorString;
    property HostName      : String         read  FHostName;
    property HostIP        : String         read  FHostIP;
    property OnDisplay     : TICMPDisplay   read  FOnDisplay write FOnDisplay;
    property OnEchoRequest : TNotifyEvent   read  FOnEchoRequest
                                            write FOnEchoRequest;
    property OnEchoReply   : TICMPReply     read  FOnEchoReply
                                            write FOnEchoReply;
  end;

  TICMPException = class(Exception);

implementation

{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
constructor TICMP.Create;
var
    WSAData: TWSAData;
begin
    hICMP    := INVALID_HANDLE_VALUE;
    FSize    := 56;
    FTTL     := 64;
    FTimeOut := 4000;

    // initialise winsock
    if WSAStartup($101, WSAData) <> 0 then
        raise TICMPException.Create('Error initialising Winsock');

    // register the icmp.dll stuff
    hICMPdll := LoadLibrary(icmpDLL);
    if hICMPdll = 0 then
        raise TICMPException.Create('Unable to register ' + icmpDLL);

    @ICMPCreateFile  := GetProcAddress(hICMPdll, 'IcmpCreateFile');
    @IcmpCloseHandle := GetProcAddress(hICMPdll, 'IcmpCloseHandle');
    @IcmpSendEcho    := GetProcAddress(hICMPdll, 'IcmpSendEcho');

    if (@ICMPCreateFile = Nil) or
       (@IcmpCloseHandle = Nil) or
       (@IcmpSendEcho = Nil) then
          raise TICMPException.Create('Error loading dll functions');

    hICMP := IcmpCreateFile;
    if hICMP = INVALID_HANDLE_VALUE then
        raise TICMPException.Create('Unable to get ping handle');
end;


{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
destructor TICMP.Destroy;
begin
    if hICMP <> INVALID_HANDLE_VALUE then
        IcmpCloseHandle(hICMP);
    if hICMPdll <> 0 then
        FreeLibrary(hICMPdll);
    WSACleanup;
    inherited Destroy;
end;


{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
function MinInteger(X, Y: Integer): Integer;
begin
    if X >= Y then
        Result := Y
    else
        Result := X;
end;


{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
procedure TICMP.ResolveAddr;
var
    Phe : PHostEnt;             // HostEntry buffer for name lookup
begin
    // Convert host address to IP address
    FIPAddress := inet_addr(PChar(FAddress));
    if FIPAddress <> LongInt(INADDR_NONE) then
        // Was a numeric dotted address let it in this format
        FHostName := FAddress
    else begin
        // Not a numeric dotted address, try to resolve by name
        Phe := GetHostByName(PChar(FAddress));
        if Phe = nil then begin
            FLastError := GetLastError;
            if Assigned(FOnDisplay) then
                FOnDisplay(Self, 'Unable to resolve ' + FAddress);
            Exit;
        end;

        FIPAddress := longint(plongint(Phe^.h_addr_list^)^);
        FHostName  := Phe^.h_name;
    end;

    FHostIP       := StrPas(inet_ntoa(TInAddr(FIPAddress)));
    FAddrResolved := TRUE;
end;


{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
procedure TICMP.SetAddress(Value : String);
begin
    // Only change if needed (could take a long time)
    if FAddress = Value then
        Exit;
    FAddress      := Value;
    FAddrResolved := FALSE;
//    ResolveAddr;
end;


{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
function TICMP.GetErrorString : String;
begin
    case FLastError of
    IP_SUCCESS:               Result := 'No error';
    IP_BUF_TOO_SMALL:         Result := 'Buffer too small';
    IP_DEST_NET_UNREACHABLE:  Result := 'Destination network unreachable';
    IP_DEST_HOST_UNREACHABLE: Result := 'Destination host unreachable';
    IP_DEST_PROT_UNREACHABLE: Result := 'Destination protocol unreachable';
    IP_DEST_PORT_UNREACHABLE: Result := 'Destination port unreachable';
    IP_NO_RESOURCES:          Result := 'No resources';
    IP_BAD_OPTION:            Result := 'Bad option';
    IP_HW_ERROR:              Result := 'Hardware error';
    IP_PACKET_TOO_BIG:        Result := 'Packet too big';
    IP_REQ_TIMED_OUT:         Result := 'Request timed out';
    IP_BAD_REQ:               Result := 'Bad request';
    IP_BAD_ROUTE:             Result := 'Bad route';
    IP_TTL_EXPIRED_TRANSIT:   Result := 'TTL expired in transit';
    IP_TTL_EXPIRED_REASSEM:   Result := 'TTL expired in reassembly';
    IP_PARAM_PROBLEM:         Result := 'Parameter problem';
    IP_SOURCE_QUENCH:         Result := 'Source quench';
    IP_OPTION_TOO_BIG:        Result := 'Option too big';
    IP_BAD_DESTINATION:       Result := 'Bad Destination';
    IP_ADDR_DELETED:          Result := 'Address deleted';
    IP_SPEC_MTU_CHANGE:       Result := 'Spec MTU change';
    IP_MTU_CHANGE:            Result := 'MTU change';
    IP_GENERAL_FAILURE:       Result := 'General failure';
    IP_PENDING:               Result := 'Pending';
    else
        Result := 'ICMP error #' + IntToStr(FLastError);
    end;
end;


{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
function TICMP.Ping : Integer;
var
  BufferSize:        Integer;
  pReqData, pData:   Pointer;
  pIPE:              PIcmpEchoReply;       // ICMP Echo reply buffer
  IPOpt:             TIPOptionInformation; // IP Options for packet to send
  Msg:               String;
begin
    Result     := 0;
    FLastError := 0;

    if not FAddrResolved then
        ResolveAddr;

    if FIPAddress = LongInt(INADDR_NONE) then begin
        FLastError := IP_BAD_DESTINATION;
        if Assigned(FOnDisplay) then
            FOnDisplay(Self, 'Invalid host address');
        Exit;
    end;

    // Allocate space for data buffer space
    BufferSize := SizeOf(TICMPEchoReply) + FSize;
    GetMem(pReqData, FSize);
    GetMem(pData,    FSize);
    GetMem(pIPE,     BufferSize);

    try
        // Fill data buffer with some data bytes
        FillChar(pReqData^, FSize, $20);
        Msg := 'Pinging from Delphi code written by F. Piette';
        Move(Msg[1], pReqData^, MinInteger(FSize, Length(Msg)));

        pIPE^.Data := pData;
        FillChar(pIPE^, SizeOf(pIPE^), 0);

        if Assigned(FOnEchoRequest) then
            FOnEchoRequest(Self);

        FillChar(IPOpt, SizeOf(IPOpt), 0);
        IPOpt.TTL   := FTTL;
        IPOpt.Flags := FFlags;
        Result      := IcmpSendEcho(hICMP, FIPAddress, pReqData, FSize,
                                    @IPOpt, pIPE, BufferSize, FTimeOut);
        FLastError  := GetLastError;
        FReply      := pIPE^;

        if Assigned(FOnEchoReply) then
            FOnEchoReply(Self, Result);
    finally
        // Free those buffers
        FreeMem(pIPE);
        FreeMem(pData);
        FreeMem(pReqData);
    end;
end;

{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}

end.



 

by: DelphiwizardPosted on 2004-12-15 at 00:02:50ID: 12827439

It works PERFECT.
Thanks to you all and especially Rlibby for the great solution (and of course Franois PIETTE)

20120131-EE-VQP-002

3 Ways to Join

30-Day Free Trial

The Experts

98% positive feedback on 31,087 answers since March 2000. angeliii is a Microsoft Most Valuable Professional for his work with MS SQL Server & Develoment.

He has also proven his knowledge of Visual Basic Programming, PHP Scripting and Oracle Databases.

The Experts

97% positive feedback on 10,752 answers since July 2000. lrmoore has more than 18 years experience in the networking industry.

The six-time Mircosoft MVPs specialties include firewalls, virtual private networking, and network management.

Testimonials

"...and excellent source for support... Kind of like having your very own IT dept." Electriciansnet

Testimonials

"I was apprehensive at signing up at first. However... it has already made my life as an IT administrator much easier." JaCrews

Testimonials

"WOW! You guys have great, active, and knowledgeable people on here." moore50

Business Clients

Business Clients

In the Press

"If you’ve got a question... Experts Exchange can supply an answer.”

In the Press

"...an invaluable aid for both IT professionals and those who require tech support."

In the Press

"where IT professionals provide quick answers on just about any topic"

Business Account Plans

Loading Advertisement...