Monday 23 June 2008

Executing external applications

Some interesting information about setting up an external application (command line) and executing it without a visible window. Allows for capturing the stdout, stdin and stderr streams too. This example is for launching the command line svn client with info argument about a specific file in the svn repository, and capturing the result of our query.

   1:  Process svnProcess = new Process();
   2:  svnProcess.StartInfo.FileName = "svn.exe";
   3:  svnProcess.StartInfo.Arguments = " info " + svnUri;
   4:  svnProcess.StartInfo.UseShellExecute = false;
   5:  svnProcess.StartInfo.RedirectStandardOutput = true;
   6:  svnProcess.StartInfo.RedirectStandardError = true;
   7:  svnProcess.StartInfo.RedirectStandardInput = true;
   8:  svnProcess.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
   9:  svnProcess.StartInfo.CreateNoWindow = true;
  10:   
  11:  try
  12:  {
  13:      bool started = svnProcess.Start();
  14:      if (!started)
  15:      {
  16:          Log.WriteLog("Unable to start svn.exe process, aborting.", "svnInfoError.log", true, true);
  17:          MessageBox.Show("Unable to start svn.exe process.", "Error launching svn.exe", MessageBoxButtons.OK, MessageBoxIcon.Error);
  18:          return -1;
  19:      }
  20:  }
  21:  catch (Exception ex)
  22:  {
  23:      Log.WriteLog("Unable to start svn.exe process, aborting.", "svnInfoError.log", true, true);
  24:      MessageBox.Show("Unable to start svn.exe process.", "Error launching svn.exe", MessageBoxButtons.OK, MessageBoxIcon.Error);
  25:      return -1;
  26:  }
  27:   
  28:  StreamReader sOut = svnProcess.StandardOutput;
  29:  string output;
  30:   
  31:  while (svnProcess.HasExited == false)
  32:  {
  33:      output = sOut.ReadLine();
  34:      if (output != null)
  35:      {
  36:          if (output.StartsWith("Last Changed Rev: "))
  37:          {
  38:              string revNumberString = output.Substring("Last Changed Rev: ".Length);
  39:              int revNumber;
  40:              if (int.TryParse(revNumberString, out revNumber))
  41:              {
  42:                  sOut.Close();
  43:                  return revNumber;
  44:              }
  45:              else
  46:              {
  47:                  throw new Exception("Could not parse the svn revision number!!!");
  48:              }
  49:          }
  50:      }
  51:  }
  52:   
  53:  do
  54:  {
  55:      output = sOut.ReadLine();
  56:      if (output != null)
  57:      {
  58:          if (output.StartsWith("Last Changed Rev: "))
  59:          {
  60:              string revNumberString = output.Substring("Last Changed Rev: ".Length);
  61:              int revNumber;
  62:              if (int.TryParse(revNumberString, out revNumber))
  63:              {
  64:                  sOut.Close();
  65:                  return revNumber;
  66:              }
  67:              else
  68:              {
  69:                  throw new Exception("Could not parse the svn revision number!!!");
  70:              }
  71:          }
  72:      }
  73:  } while (output != null);
  74:   
  75:   
  76:  string error = svnProcess.StandardError.ReadToEnd();
  77:  if (string.IsNullOrEmpty(error) == false)
  78:  {
  79:      Log.WriteLog(error, "svnInfoError.log", true, true);
  80:   
  81:  }
  82:  return -1; // Error executing the svn client application!!!

Friday 20 June 2008

Ankhsvn, VS 2008 and subversion.

Today I realised that Ankhsvn, VS 2008 and subversion don't play very well together. As soon as I installed subversion my Ankhsvn VS 2008 plugin refused to work. Tried uninstalling it and installing every possible version with no success.

The final solution was to remove subversion, and just use the subversion zip file to extract the executable that I needed. It seems that the problem is some conflict between the subversion installer and Ankhsvn. In any case I am glad I managed to resolve this.

Thursday 19 June 2008

.NET events and event handlers

This is a simple description of events and handlers. Does not include custom event arguments.

Child class is the source of the events and Parent class is the sink or consumer of the events. The parent reacts to events originating at the child class.

1. In child class:

A. Declare a delegate defining the signature of event handlers. Parent class functions that handle our events need to implement this delegate. This delegate is required in order to define events in this class.

Example: child class is Car, containing the following delegate:


   1:  public delegate void CarEventHandler(string msg);

B. Declare event names and associate them to the delegate above. These are events this class can send out to subscribers.

Example:


   1:  public event CarEventHandler Exploded;
   2:  public event CarEventHandler AboutToBlow;

C. When certain conditions are met, first check event for null and fire it (with same parameters as the delegate - these will be passed on to the handler).

Example:


   1:  public void Accelerate(int delta)
   2:  {
   3:      // If the car is dead, fire Exploded event.
   4:      if (carIsDead)
   5:          if (Exploded != null)
   6:              Exploded(this, new CarEventArgs("Sorry, this car is dead..."));
   7:  }


2. In parent class:

A. Define one or more functions implementing the event delegate that will perform the action required when the event fires.

Example:


   1:  public static void CarExploded(string msg)
   2:  {
   3:      Console.WriteLine(msg);
   4:  }

B. Create an event handler, associating it with the handling function in the child class, as defined above.


   1:  Car.CarEventHandler carExplodedEventHandler = new Car.CarEventHandler(CarExploded);

C. Register the handler we created with the child class event type we want to handle (usually right after we create this object). If c1 is an object of the type in the child class,


   1:  c1.Exploded += carExplodedEventHandler ;


Now whenever the event fires in the child class, the delegate will execute the CarExploded(string msg) function in the parent class.


   1:  public void Accelerate(int delta)
   2:  {
   3:      // If the car is dead, fire Exploded event.
   4:      if (carIsDead)
   5:      if (Exploded != null)
   6:      Exploded(this,
   7:      new CarEventArgs("Sorry, this car is dead..."));
   8:  }

IMPORTANT NOTE: If you want to refer to a non static function (to fire when the event occurs i.e. function CarExploded in this example) you need to declare it at the class level, but initialise it in the parent class constructor. When declaring the event handler you can declare it readonly. I.e.:

Step 2B becomes:


   1:  readonly Car.CarEventHandler carExplodedEventHandler; // above the constructor

and inside the constructor:


   1:  carExplodedEventHandler = CarExploded;