Tuesday, March 27, 2012

Reading redirected output of the process: limitations and how to work around

During last month I was working on a project built on top of the Console-windows. An interesting problem I was facing is the read of redirected output (asyncronous) from that process. It seems to be quite easy to handle such a task, and it is, unless you need to read "all the output".
Well, the simple approach of handling such a task is like the following:
1. Define a ProcessStartInfo with redirected output:
    ProcessStartInfo tmpStartInfo = new ProcessStartInfo()
    {
        FileName = "consoleApp.exe",
        UseShellExecute = false,
        RedirectStandardOutput = true
    }
2. Create a process and set the start info to alrelady defined one:
    ProcessStartInfo tmpProcess = new Process()
    tmpProcess.StartInfo = tmpStartInfo;
3. Define and register a handler for the OutputDataReceived event:
    private static void Process_OutputDataReceived(object sendingProcess, DataReceivedEventArgs outLine)
    {
        Console.WriteLine(outLine);
    }
    tmpProcess.OutputDataReceived += new DataReceivedEventHandler (Process_OutputDataReceived);

4. Start the process.
    tmpProcess.Start();

Yes, it's simple, but there is an open issue left in here. The process won't redirect the output, until there is a new-line character in the stream, which means, that the Process will fire the OutputDataReceived event only as soon as a new line is available on the stream. So for me this was a big limitation, because if the process is writing something on a line and still waits for some input from the user on the same line, we will never receive that line, and won't even know that the process is waiting for user input there.
To fix this we need to observe the stream on our own, not awaiting the event to fire. So, here is the algorithm I came up with, to handle the behavior described:
   
private void ObserveStreamInBackground()
{
  try
  {
    char? tmpStreamChar = null;
    do
    {
      int tmpStatus = this.Stream.Peek();
      if (tmpStatus == -1)
      {
        if (this.messageBuffer.Length > 0)
        {
          this.InformMessage();
        }
        tmpStreamChar = (char)this.Stream.Read();
      }
      char tmpCurrentChar = tmpStreamChar ?? (char)this.Stream.Read();
      if (tmpStreamChar.HasValue)
      {
        tmpStreamChar = null;
      }
      this.messageBuffer.Append(tmpCurrentChar);
      if (tmpCurrentChar == '\n')
      {
        this.InformMessage();
      }
    } while (true);
   }
  catch (ThreadAbortException ex)
  {
  }
}

private void InformMessage()
{
  string tmpMessage = this.messageBuffer.ToString();
  this.messageBuffer.Clear();
  this.lastMessage = tmpMessage;
  this.lastMessageReceivedAt = DateTime.Now;
  this.OnMessageReceived(tmpMessage);
}

The InformMessage() method is there to just clear the current message buffer and fire the event with the message data in it.
That's all. Experiment with it and give me your feedback. Good Luck !

Friday, March 9, 2012

Reflection: working with generic types


An interesting problem I was facing during last few days drives me to write this post. The problem was to create a generic type instance (let's say List), the type parameter for which is known only during runtime. Let's examine the following code fragment:
Type genericListOfInt = typeof(List<int>);
Type genericListOfString = typeof(List<string>);
bool sameType = genericListOfInt == genericListOfString;
//sameType is false here, so those Types are differenet
Both the variables seems to be instances of the same List (List of T) type, but because the T type parameter is different the compiler will generate two different classes for List and List so the variables will not be equal. But how to handle the problem we do face ?
Examining the System.Type class we will find out a very interesting method called:GetGenericTypeDefinition() method. This method returns a Type object, representing the generic type definition, from which the type, which for the method was called, was constructed, so actually the type, which can be used to construct other Generic types as well.
So modifying the code above will give us the following:
Type genericListOfInt = typeof(List<int>);
Type genericListOfString = typeof(List<string>);

bool sameType = genericListOfInt == genericListOfString;
//sameType variable is true now, so both variables are referencing the same Type instance
Apparently, the type, which is reffered by both genericListOfInt and genericListOfString variables can be accessed with the following variable as well:
Type genericList = typeof(List<>);
This makes it really handy, so we don't want the compiler to generate any classed which are actually useless just to get the reference to a generic type.
Now this type can be used to construct different Lists for different types dynamically (List<[any type you want here]>). So here is a simple code for constructing a list of the given type:
public static object CreateGenericList(Type ofType)
{
  Type genericListType = typeof(List<>);
  return Activator.CreateInstance(genericListType.MakeGenericType(new Type[]{ofType}));
}
Please note also, that the List type was taken for example only, so to access multi-type based generic type (like KeyValuePair<k,v>) you can easily use the same technique:
Type genericKVPair = typeof(KeyValuePair<,>);
Now, the last scenario left to discuss, is how to dynamically identify the generic type parameters a type has (string in case of List and (int, string) in case of KeyValuePair)? The Type class defines another interesting method called GetGenericArguments(), which returns an Array of Type objects. Combining this method with MakeGenericType will let us write the following code, which is used to build a KeyValuePair of Types, which are the switch from the original one by type parameter places (for KeyValuePair it will return KeyValuePair):
public object CreateInstnaceOfTheSameType(object original)
{
  if (original == null)
  {
    return null;
  }

  Type origType = original.GetType();
  if (!origType.IsGenericType || origType.GetGenericTypeDefinition() != typeof(KeyValuePair<,>)
  {
    throw new ArgumentException("KeyValuePairs expected");
  }

  Type[] typeArgs = origType.GetGenericArguments();
  Type typeToConstruct = origType.GetGenericTypeDefinition().MakeGenericType(new Type[] { typeArgs[1], typeArgs[0]});
  object[] constructorParams;
  // I'm skipping the code for constructorParams initialization, cause it's out of scope
  return Activator.CreateInstance(typeToConstruct, constructorParams);
}
Hope you will find this post helpful.

Regards...