<$BlogRSDUrl$>

Friday, October 24, 2003

Even Better Ping in C# 

Alright, the flash of the shell window bothered me even more than I thought.

Diving into the .Net Framework uncovered the System.Diagnostics.Process class. The Process class can use a ProcessStartInfo class which has a RedirectStandardOutput property that returns a StreamReader, which is excactly what I was looking for.

Here's the updated CSharp class. Note that there's no error handling, (probably need a try block around the objProc.Start method):
//----------------------------------------+----------------------------------------
// TCPIPServices - Namespace for TCPIP functions
//
// Date   Name    Comment
// ------ ------- -----------------------------------------------------------------
// 031021 CGL     Created
//----------------------------------------+----------------------------------------
using System;
using System.IO;
using System.Diagnostics;
using System.Text.RegularExpressions;

namespace TCPIPServices
{
  /// <summary>
  /// CTCPIPServices - Class of TCP/IP Services
  /// </summary>
  /// <remarks>
  /// TODO: NSLookup, NetStat, etc
  /// </remarks>
  public class CTCPIPServices
  {
    /// <summary>
    /// The class constructor. 
    /// </summary>
    public CTCPIPServices()
    {
    }

    /// <summary>
    /// Ping using Ping.EXE
    /// </summary>
    /// <param name="HostName">Host to Ping</param>
    /// <remarks>
    /// Creates a new procsses to execute the PING.EXE command and capture output, which
    /// is then parsed to determine results.
    /// </remarks>
    /// <returns>
    /// Returns true if ping succeeded, false if ping fails.
    /// </returns>
    public bool Ping(string HostName) 
    {
      Process objProc = new Process();
      string strCommand = "PING.EXE ";
      string strLine;
      Regex  objRegExp;

      objProc.StartInfo.FileName = strCommand;
      objProc.StartInfo.Arguments = HostName;
      objProc.StartInfo.UseShellExecute = false;
      objProc.StartInfo.RedirectStandardOutput = true;
      //objProc.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
      objProc.StartInfo.CreateNoWindow = true;
      objProc.Start();
      objProc.WaitForExit();

      //Read the output from the command
      while (objProc.StandardOutput.Peek() >= 0) 
      {
        strLine = objProc.StandardOutput.ReadLine();
        strLine = strLine.Trim();
        
        //test for Unknown Host
        objRegExp = new Regex("^Unknown", RegexOptions.IgnoreCase);
        if (objRegExp.IsMatch(strLine))
        {
          return false;
        }
        
        //DNS Succeeded, but box off-line
        objRegExp = new Regex("100% loss", RegexOptions.IgnoreCase);
        if (objRegExp.IsMatch(strLine))
        {
          return false;
        }

        //Got a reply
        objRegExp = new Regex("^Reply from", RegexOptions.IgnoreCase);
        if (objRegExp.IsMatch(strLine))
        {
          //Check for "Destination host unreachable."
          objRegExp = new Regex("Destination host unreachable", RegexOptions.IgnoreCase);
          if (objRegExp.IsMatch(strLine))
          {
            return false;
          } 
          else 
          {
            return true;
          }
        }
      }
      //Should never get here...
      return false;
    }
  }
}
Copyright © 2003, Christopher G. Lewis
|

Tuesday, October 21, 2003

Simple Ping in VBScript & C# 

As you might have seen from my web site, I've played with the System.Net namespace to create an ICMP version of ping in C#. Interesting in it's own right, but it's a lot of low level code.

I started looking for a simpler way to ping and return a result.

WMI supports a ping class, but only in XP and above.

With VBScript, you can use the WshShell.Exec command to exec Ping.EXE and parse the result as follows (variations of this are readily available in Google Groups):

'----------------------------------------+----------------------------------------
' Ping - Pings a host via Shell, and parses the results
'
' Date   Name    Comment
' ------ ------- -----------------------------------------------------------------
' 030620 CGL     Created
'----------------------------------------+----------------------------------------
Function Ping(strHost)
  Dim objShell
  Dim objStdOut
  Dim strLine
  Dim objRegExp
  Dim strPattern

  Ping = False

  Set objShell = WshShell.Exec("PING.EXE " & strHost)  'The command line
  Set objStdOut = objShell.StdOut 'Reads the output from the command
  Set objRegExp = New RegExp
  objRegExp.IgnoreCase = True

  Do While Not objStdOut.AtEndOfStream
    strLine = objStdOut.ReadLine
    strLine = Trim(strLine)
    'Test for "Unknown Host" - DNS Failed
    objRegExp.Pattern = "^Unknown"
    If objRegExp.Test(strLine) Then
      Ping = False
      Exit Function
    End If

    'DNS Succeeded, but box off-line
    objRegExp.Pattern = "100% loss"
    If objRegExp.Test(strLine) Then
      Ping = False
      Exit Function
    End If

    'Got a Reply From,
    objRegExp.Pattern = "^Reply from"
    If objRegExp.Test(strLine) Then
      'Check for "Destination host unreachable."
      objRegExp.Pattern = "Destination host unreachable\."
      If objRegExp.Test(strLine) Then
        Ping = False
      Else
        'S/B OK here
        Ping = True
      End If
      Exit Function
    End If
  Loop

  Set objShell = Nothing
  Set objStdOut = Nothing
  Set objRegExp = Nothing
End Function
Duplicating the key points of this code in CSharp results in the following:
//----------------------------------------+----------------------------------------
// TCPIPServices - Namespace for TCPIP functions
//
// Date   Name    Comment
// ------ ------- -----------------------------------------------------------------
// 031021 CGL     Created
//----------------------------------------+----------------------------------------
using System;
using System.Text.RegularExpressions;

//Reference to: Windows Script Host Object Model
using IWshRuntimeLibrary;

namespace TCPIPServices
{
  /// <summary>
  /// CTCPIPServices - Class of TCP/IP Services
  /// </summary>
  /// <remarks>
  /// TODO: NSLookup, NetStat, etc
  /// </remarks>
  public class CTCPIPServices
  {
    /// <summary>
    /// The class constructor. 
    /// </summary>
    public CTCPIPServices()
    {
    }

    /// <summary>
    /// Ping using Ping.EXE
    /// </summary>
    /// <param name="HostName">Host to Ping</param>
    /// <remarks>
    /// Uses WSH 5.6 to exec the PING.EXE command and capture output, which
    /// is then parsed to determine results
    /// </remarks>
    /// <returns>
    /// Returns true if ping succeeded, false if ping fails.
    /// </returns>
    public bool Ping(string HostName) 
    {
      IWshRuntimeLibrary.WshShell     objShell = new IWshRuntimeLibrary.WshShell();
      IWshRuntimeLibrary.TextStream   tsStdOut;
      string                          strCommand = "PING.EXE " + HostName;
      string                          strLine;
      Regex  objRegExp;

      IWshRuntimeLibrary.IWshExec objExec = objShell.Exec(strCommand);
      tsStdOut = objExec.StdOut; //Reads the output from the command
      while (!tsStdOut.AtEndOfStream) 
      {
        strLine = tsStdOut.ReadLine();
        strLine = strLine.Trim();
        
        //test for Unknown Host
        objRegExp = new Regex("^Unknown", RegexOptions.IgnoreCase);
        if (objRegExp.IsMatch(strLine))
        {
          return false;
        }
        
        //DNS Succeeded, but box off-line
        objRegExp = new Regex("100% loss", RegexOptions.IgnoreCase);
        if (objRegExp.IsMatch(strLine))
        {
          return false;
        }

        //Got a reply
        objRegExp = new Regex("^Reply from", RegexOptions.IgnoreCase);
        if (objRegExp.IsMatch(strLine))
        {
          //Check for "Destination host unreachable."
          objRegExp = new Regex("Destination host unreachable", RegexOptions.IgnoreCase);
          if (objRegExp.IsMatch(strLine))
          {
            return false;
          } 
          else 
          {
            return true;
          }
        }
      }
      //Should never get here...
      return false;
    }
  }
}
The weird thing about the WshShell.Exec command is that you can see the window. No way that I know of to hide it.

In my opinion, not a big deal, but I'm hunting for a better solution.

Copyright © 2003, Christopher G. Lewis
|

This page is powered by Blogger. Isn't yours? Weblog Commenting and Trackback by HaloScan.com