Tuesday, June 16, 2009

Using the Process class.

I was not too loaded with work recently so I decided to write a small application that would help to automate the process of converting existing Visual SourceSafe projects to Team Foundation Server. The idea is to get some information from the user first, and then spare him from some manual tasks - running tools like ssarc, ssrestor or VSSConverter, manually creating and editing XML files etc.

When the application starts, the user needs to provide (or just check) the following information:

  • A folder where Visual SourceSafe is installed
  • A folder where Visual SourceSafe database is located
  • Visual SourceSafe database administrator login credentials
  • The name of the Visual SourceSafe project to be converted
  • A folder that will be used during conversion to restore VSS database, keep XML files etc.
  • SQL Server that will be used by the converter
  • A name of the TFS and the port number
  • A name of the project on the TFS where the converted files will go

A significant chunk of the application functionality is just wrapping the calls to command line tools so that the user does not have to bother with manually locating them, typing the correct parameters etc.

For that purpose, the .NET class Process is quite handy.
Here is the example:
To archive the VSS project MyProject which is in the VSS database located on MyServer into the archive file called MyArchive.ssa I need to run the following from the command line:

>"C:\Program Files\Microsoft Visual SourceSafe\ssarc.exe" "-d- -i -yadmin,password -s\\MyServer\ MyArchive.ssa \$/MyProject\"

To run this command from the C# code I can use the following code:

ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.FileName = "ssarc.exe";
startInfo.Arguments = @"-d- -i -yadmin,password -s\\MyServer\ MyArchive.ssa \$/MyProject\";
startInfo.WorkingDirectory = @"C:\Program Files\Microsoft Visual SourceSafe";
Process process = Process.Start(startInfo);

This is quite self-explanatory.

There are a couple of things that I had trouble with however. First thing is logging. It would be nice to log the errors and messages that the process generates. This is possible, according to the MSDN article.

ProcessStartInfo Class

Standard input is usually the keyboard, and standard output and standard error are usually the monitor screen. However, you can use the RedirectStandardInput, RedirectStandardOutput, and RedirectStandardError properties to cause the process to get input from or return output to a file or other device. If you use the StandardInput, StandardOutput, or StandardError properties on the Process component, you must first set the corresponding value on the ProcessStartInfo property. Otherwise, the system throws an exception when you read or write to the stream.

However, if I redirect standard output to the text file, for example, the user is unable to see it. And some of the tools used required interaction with the user. So it looks like I either interact with the user, or log the messages somewhere.

Also, when the process completes, it closes the window where it was running. So, if there is a message shown by the process when it exits, the user does not have time to read it. It might be frustrating when the process exits with an error message and the user does not know what exactly the error was. And it can not be logged because the output can not be redirected somewhere - the user needs to see it on the screen.

I will still be looking for the 'elegant' solution for this, but so far I found a workaround: rather than starting the process itself, I can start the command line using the "cmd.exe" and pass the whole tool together with the parameters as a parameter to cmd.exe.

CMD

The trick is that specifying the /k parameter prevents the command window from closing after the process exits. Here is how the previous code will look like when changed according to my workaround:

ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.FileName = "cmd.exe";
startInfo.Arguments = @"/k "C:\Program Files\Microsoft Visual SourceSafe\ssarc.exe" "-d- -i -yadmin,password -s\\MyServer\ MyArchive.ssa \$/MyProject\"";
Process process = Process.Start(startInfo);

I will be looking for a better solution when I have time to improve this application.

by . Also posted on my website

No comments: