July 9, 2010

Close or Kill a Process

This routine will try and close a process by sending a close message to it's main window. If the process has no GUI or a timeout period is exceeded then the 'Process.Kill()' method will be used to close it.
// Try and close a process. Kill it if the Close takes 
// too long.
// exeLessExtension - Process name (without extension)
// msToWaitForCloseMainWindow - Time in milliseconds to
// wait for 'CloseMainWindow()' before just killing the 
// process, Set negative to not kill at all, set to 0 to 
// kill without calling CloseMainWindow
public static void ForceProcessClose(
  string exeLessExtension, 
  int msToWaitForCloseMainWindow)
{
  Process[] processes = Process.GetProcessesByName(exeLessExtension);

  if (msToWaitForCloseMainWindow != 0)
  {
    foreach (Process p in processes)
    {
      if (!p.CloseMainWindow())
      {   // Process does not have a GUI, use 'Kill()' instead
         msToWaitForCloseMainWindow = 0;
      }
    }
  }
  if (msToWaitForCloseMainWindow >= 0)
  {
    Thread.Sleep(msToWaitForCloseMainWindow);
    processes = Process.GetProcessesByName(exeLessExtension);
    foreach (Process p in processes)
    {
       p.Kill();
    }
  }
}

July 1, 2010

Using Images in WPF

Using project resources in WPF
  1. Create sub-directory for resources called say "Resources"
  2. Add your resources (images, icons etc.) to it.
  3. Copy the folder structure into the VS project and add the resource files to it.
  4. Check the Properties of your resources in VS project file to ensure they have a Build Action of 'Resource'
Creating an image in WPF: In XAML:
<Image Source="Resources/P4.ico" />
Adding an image to a window's resources is very easy:
<Window.Resources>
        <Image x:Key="P4Icon" Source="Resources/P4.ico" />
</Window.Resources>
In code:
Image myImage = new Image();
myImage.Source = new BitmapImage(new Uri("Icons/MyImage.png", UriKind.Relative));
Inserting an image in a button is very easy in WPF:
<Button HorizontalAlignment="Left" Margin="5,8,0,10" Name="p4But" Width="34" Click="p4But_Click">
   <Image Source="Resources/P4.ico" Width="24" />
</Button>

Start a Process and Capture the Output in c#

Simple sample for running a process synchronously and capturing the output
public string GetEnvironmentVars()
{
    Process process = new Process();
    // UseShellExecute must be 'false' when redirecting the output
    process.StartInfo.UseShellExecute = false;
    process.StartInfo.RedirectStandardOutput = true;
    process.StartInfo.RedirectStandardError = true;
    process.StartInfo.CreateNoWindow = true;
    process.StartInfo.FileName = "p4";
    process.StartInfo.Arguments = " set ";
    //process.StartInfo.WorkingDirectory = dir;
    process.Start();
    string output = process.StandardOutput.ReadToEnd();
    //string error = process.StandardError.ReadToEnd();
    // Wait a reasonable ammount of time for it to finish
    bool res = process.WaitForExit(5000); 
    return res ? output : "Command \"" + 
        process.StartInfo.FileName + process.StartInfo.Arguments +
        "\" failed to exit:" + Environment.NewLine + output;
}

Editing Context Menus of Visual Studio 2008

Can add external tools to context menu.
  1. Create your external tool using the "Tools=>External Tools" menu option. Your new external tool will be called "External Command n" where 'n' is the external menu item tool location in the external menu items group of the Tools menu
  2. Open "Tools=>Customize" dialog.
  3. Select "Context Menus" in the "Toolbars" tab.
  4. The context menus will appear on the toolbar. Select a context menu from one on the toolbar. Some useful ones are:
    • "Project and Solution Context Menus=>Item" - This is the file context menu in the solutions folder
    • "Project and Solution Context Menus=>Project" - This is the project context menu in the solutions folder
    • "Other Context Menus=>Easy MDI Document Window" - Not obvious. This is the context menu for the tab at the top of a file editor window
  5. Goto "Command" tab and select "Tools" in the categories tab. From the "Commands:" list select the appropriate "External Command n"
Perforce menu items are defined in "External Tools" as follows:
Title: P4 Checkout
Command: C:\Program Files (x86)\Perforce\p4.exe
Arguments: edit $(ItemPath)
Initial Directory: $(ItemDir)
Select "Use Output window"
As shown here:

Title: P4 Revert
Command: C:\Program Files (x86)\Perforce\p4.exe
Arguments: revert $(ItemPath)
Initial Directory: $(ItemDir)
Select "Use Output window"

June 29, 2010

Open An EMail In Outlook

If are running a PC with Outlook and you want to open an email using Outlook from your application (but not send it immediately)
Following sample opens an email dialog with a specified document already attached
private void butEMailFiles_Click(object sender, RoutedEventArgs e)
{
    string archiveName = GetExistingArchiveName();
    if (File.Exists(archiveName))
    {
        RunShellCommand("Outlook.exe", "/a \"" + archiveName + "\""); 
    }
}

private static void RunShellCommand(string app, string args)
{
    string dir = System.IO.Path.GetDirectoryName(app);
    string file = System.IO.Path.GetFileName(app);

    Process process = new Process();
    process.StartInfo.FileName = file;
    process.StartInfo.WorkingDirectory = dir;
    process.StartInfo.Arguments = args;
    process.Start();
}

Run Batch File in C#

Quick method to create and run a batch file, the contents of which are passed as a string.
private void RunBatchFile(
  string batFileContents, 
  int waitToFinishSecs)
{
    string batFile = Path.GetTempFileName();
    batFile = batFile.Replace(".tmp", ".bat");
    File.WriteAllText(batFile, batFileContents);
    string dir = System.IO.Path.GetDirectoryName(batFile);
    string file = System.IO.Path.GetFileName(batFile);

    Process process = new Process();
    process.StartInfo.FileName = file;
    process.StartInfo.WorkingDirectory = dir;
    bool res = false; // Dont do anything with this yet
    try
    {
        process.Start();
        res = process.WaitForExit(waitToFinishSecs*1000);
        File.Delete(batFile);
    }
    catch (Win32Exception winex)
    {
        Debug.WriteLine(winex.ToString());
        throw;
    }    
}

June 10, 2010

Sweepstake Generator

Highly topical now the world cup is on! Here is my sweepstake generator class
class SweepstakeGenerator
{
  public class PlayerTeamPair
  {
    public string Player { get; set; }
    public string Team { get; set; }
    public override string ToString()
    {
      return (string.IsNullOrEmpty(Team) || string.IsNullOrEmpty(Player)) ? 
        "" : Team + " - " + Player;
    }
  }

  public static IEnumerable AssignTeams(
    IEnumerable orderedTeams, 
    IEnumerable namesArray)
  {
    Debug.Assert(namesArray.Count() > 0, "No names in the names array!");
    List names = new List();
    List teams = new List(orderedTeams);
    List assignedTeams = new List(teams.Count);
    Random random = new Random();
    int teamIx = 0;
    while (teamIx < teams.Count)
    {
      if (names.Count == 0)
      {
        names = names = new List(namesArray);
      }
      int nameIx = random.Next(0, names.Count);
      assignedTeams.Add(new PlayerTeamPair() { 
        Team = teams[teamIx], 
        Player = names[nameIx] });
      //Debug.WriteLine(teams[teamIx] + " - " + names[nameIx]);
      //Console.WriteLine(teams[teamIx] + " - " + names[nameIx]);
      names.RemoveAt(nameIx);
      teamIx++;
    }
    return assignedTeams;
  }
}
and sample usage
string[] teamsOrderedByBettingOdds = new string[] { 
 "Spain", "Brazil", "Argentina", "England",
 "Holland", "Germany", "Italy", "France",
 "Portugal", "Ivory Coast", "Serbia", "Mexico",
 "Chile", "USA", "Paraguay", "Uruguay",
 "Cameroon", "South Africa", "Ghana", "Australia",
 "Denmark", "Nigeria", "Greece", "South Korea",
 "Switzerland", "Slovakia", "Slovenia", "Japan",
 "Algeria", "Honduras", "North Korea", "New Zealand"
 };
string[] teamsOrderedByGrouping = new string[] { 
 "France", "Mexico", "South Africa", "Uruguay",
 "Argentina", "Greece", "Nigeria", "South Korea",
 "Algeria", "England", "Slovenia", "USA",
 "Australia", "Germany", "Ghana", "Serbia",
 "Cameroon", "Denmark", "Japan", "Netherlands",
 "Italy", "New Zealand", "Paraguay", "Slovakia",
 "Brazil", "Ivory Coast", "North Korea", "Portugal",
 "Chile", "Honduras", "Spain", "Switzerland"
 };
string[] teamsOrderedTop8AndThenByGrouping = new string[] { 
 "France", "Argentina", "England", "Germany",
 "Holland", "Italy", "Brazil", "Spain",
 "Mexico", "South Africa", "Uruguay", "Greece",
 "Nigeria", "South Korea", "Algeria", "Slovenia",
 "USA", "Australia", "Ghana", "Serbia",
 "Cameroon", "Denmark", "Japan", "New Zealand",
 "Paraguay", "Slovakia", "Ivory Coast", "North Korea",
 "Portugal", "Chile", "Honduras", "Switzerland" };
 
string[] namesArray = new string[] { 
  "Bob", "Ron", "Tony", "Jim", "George", "Ben", "Alf", "Dirk" };

IEnumerable playerTeamIter = 
  SweepstakeGenerator.AssignTeams(
    teamsOrderedTop8AndThenByGrouping, namesArray);
foreach (SweepstakeGenerator.PlayerTeamPair playerTeam in playerTeamIter)
{
 Debug.WriteLine(playerTeam.ToString());
}
Sample Output
France - George
Argentina - Tony
England - Alf
Germany - Ron
Holland - Bob
Italy - Jim
Brazil - Ben
Spain - Dirk
Mexico - Jim
South Africa - Ben
Uruguay - George
Greece - Dirk
Nigeria - Alf
South Korea - Ron
Algeria - Bob
Slovenia - Tony
USA - Dirk
Australia - Jim
Ghana - Alf
Serbia - George
Cameroon - Tony
Denmark - Ben
Japan - Ron
New Zealand - Bob
Paraguay - Dirk
Slovakia - Alf
Ivory Coast - Jim
North Korea - Ben
Portugal - Ron
Chile - Bob
Honduras - George
Switzerland - Tony