Showing posts with label Programming. Show all posts
Showing posts with label Programming. Show all posts

Friday, April 18, 2014

The perils of micro-optimisations

A debate has been raging on my website over the use of StringBuilder.AppendFormat in my exception logger code. OK, raging is something of an exaggeration, there have been two comments in two years. But the point made by two people is that rather than

error.AppendLine("Application: " + Application.ProductName);

I should be using

error.AppendFormat("Application: {0}\n", Application.ProductName);

Since this means I wouldn’t be using string concatenation, which is considered bad for performance reasons. My main reason for not doing anything about this is because I’m lazy, but also because the whole point of this code is that it only runs when an exception is thrown, which hopefully is a pretty rare event, so performance is not a major concern.

But then I wondered what the difference in performance is between these two approaches? So I wrote a little test application that looks like this.

    static void Main(string[] args)
    {
      for (int j = 0; j < 10; j++)
      {
        // try using AppendLine
        Console.WriteLine("AppendLine");
        StringBuilder error = new StringBuilder();
        Stopwatch sw = new Stopwatch();
        sw.Start();
        for (int i = 0; i < 1000000; i++)
        {
          error.AppendLine("Application: " + Application.ProductName);
        }
        sw.Stop();
        Console.WriteLine(sw.ElapsedMilliseconds);

        // try using AppendFormat
        Console.WriteLine("AppendFormat");
        error.Clear();

        sw.Restart();
        for (int i = 0; i < 1000000; i++)
        {
          error.AppendFormat("Application: {0}\n", Application.ProductName);
        }
        sw.Stop();
        Console.WriteLine(sw.ElapsedMilliseconds);
      }

      Console.ReadKey();
    }

The results from this app in milliseconds are as follows (reformatted for clarity)

AppendLine 307 315 321 372 394 370 289 298 300 296
AppendFormat 366 360 362 471 353 359 354 365 365 350

So which is quicker? Well it looks like AppendLine might be marginally quicker. But, much more importantly, who the feck cares? We are repeating each operation 1 million times and the time to execute is still less than half a second. Maybe you can pick holes in my test application, but again I would ask who the feck cares? Either approach is really fast.

And this is the main problem with trying to optimise this kind of stuff. We can spend huge amounts of time figuring out if one approach is quicker than another, but a lot of the time is doesn’t matter. Either the code runs quick enough using any sensible approach, or it’s hit so infrequently that even a really poor implementation will work.

Of course we should consider performance whilst writing code, but we should only use particular approaches when we know they are going to produce more performant code. A good example is the StringBuilder class. We can be pretty sure this is going to be better than using string concatenation, otherwise it wouldn’t exist in the first place. That said, if you’re concatenating two strings I really wouldn’t worry about it.

But the key to writing efficient code is to understand what is slow on a computer. Network operations are slow. Disk access is slow. Because of that, anything that requires large amounts of memory (meaning virtual memory i.e. disk access) is slow. Twiddling bits in memory is quick. Fast code is achieved by avoiding the slow stuff and not worrying about the quick stuff.

And once you’ve written your code and found it doesn’t run ask quick as you’d hoped, don’t jump in and replace calls to AppendLine with calls to AppendFormat, profile your application! Every time I profile an application, I’m always amazed at the causes of the performance bottleneck, it’s rarely where I thought it would be.

If you don’t have a profiler, use poor man’s profiling. There are also free profilers available, I quite liked the Eqatec Profiler which seems to be available from various download sites, although it’s no longer available from Eqatec. But whatever you do, don’t get into Cargo Cult Programming

Saturday, October 26, 2013

Getting the icon for the user’s default browser in C#

In my last post I showed how to get hold of the associated icon for a file. Now, say you want to get hold of the icon for the user’s default browser, you may think you can just grab the icon for HTML files and that’ll do the job. Whilst that will work for some users, it won’t work for all of them. The application used to open HTML files does not need to be the same application that is used to open websites. For example changing your default browser to Chrome won’t change the default application for HTML files to Chrome. So here’s an extension to that previous code to get the icon for the default browser. It won’t work for XP since the way default applications are handled has changed but it should work with all later OSes.

    private static string GetDefaultBrowserPath()
    {
      const string userChoice = @"Software\Microsoft\Windows\Shell\Associations\UrlAssociations\http\UserChoice";
      using (RegistryKey userChoiceKey = Registry.CurrentUser.OpenSubKey(userChoice))
      {
        if (userChoiceKey != null)
        {
          object progIdValue = userChoiceKey.GetValue("Progid");
          if (progIdValue != null)
          {
            string progId = progIdValue.ToString();
            const string exeSuffix = ".exe";
            string progIdPath = progId + @"\shell\open\command";
            using (RegistryKey pathKey = Registry.ClassesRoot.OpenSubKey(progIdPath))
            {
              if (pathKey != null)
              {
                string path = pathKey.GetValue(null).ToString().ToLower().Replace("\"", "");
                if (!path.EndsWith(exeSuffix))
                {
                  path = path.Substring(0, path.LastIndexOf(exeSuffix, StringComparison.Ordinal) + exeSuffix.Length);
                }
                return path;
              }
            }
          }
        }
      }

      return null;
    }

    public static Icon GetDefaultBrowserLargeIcon()
    {
      string browserPath = GetDefaultBrowserPath();

      if (!string.IsNullOrEmpty(browserPath))
        return GetLargeIcon(browserPath);

      // last chance (probably XP), just grab the icon for HTML files
      return GetLargeIcon("test.html");
    }

    public static Icon GetDefaultBrowserSmallIcon()
    {
      string browserPath = GetDefaultBrowserPath();

      if (!string.IsNullOrEmpty(browserPath))
        return GetSmallIcon(browserPath);

      // last chance (probably XP), just grab the icon for HTML files
      return GetSmallIcon("test.html");
    }

Getting the associated icon for a file in C#

Sometimes it’s useful to display an icon for a file in an application and probably the best icon to display is whatever the operating system uses. The Windows API provides the SHGetFileInfo function for this purpose, so here’s a little wrapper around it. All the methods take a file name parameter, but the file doesn’t need to actually exist.

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace TestIcons
{
  public static class ImageUtilities
  {
    [StructLayout(LayoutKind.Sequential)]
    struct SHFILEINFO
    {
      public IntPtr hIcon;
      public IntPtr iIcon;
      public uint dwAttributes;
      [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
      public string szDisplayName;
      [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
      public string szTypeName;
    };

    static class Win32
    {
      internal const uint SHGFI_ICON = 0x100;
      internal const uint SHGFI_LARGEICON = 0x0; // 'Large icon
      internal const uint SHGFI_SMALLICON = 0x1; // 'Small icon
      internal const uint SHGFI_USEFILEATTRIBUTES = 0x10;
      internal const uint SHGFI_LINKOVERLAY = 0x8000;

      [DllImport("shell32.dll")]
      public static extern IntPtr SHGetFileInfo(string pszPath, uint dwFileAttributes, ref SHFILEINFO psfi, uint cbSizeFileInfo, uint uFlags);

      [DllImport("User32.dll")]
      public static extern int DestroyIcon(IntPtr hIcon);
    }

    public static Icon GetSmallIcon(string fileName)
    {
      return GetIcon(fileName, Win32.SHGFI_SMALLICON);
    }

    public static Icon GetSmallOverlayIcon(string fileName)
    {
      return GetIcon(fileName, Win32.SHGFI_SMALLICON | Win32.SHGFI_LINKOVERLAY);
    }

    public static Icon GetLargeIcon(string fileName)
    {
      return GetIcon(fileName, Win32.SHGFI_LARGEICON);
    }

    private static Icon GetIcon(string fileName, uint flags)
    {
      SHFILEINFO shinfo = new SHFILEINFO();
      IntPtr hImgSmall = Win32.SHGetFileInfo(fileName, 0, ref shinfo, (uint)Marshal.SizeOf(shinfo),
        Win32.SHGFI_ICON | Win32.SHGFI_USEFILEATTRIBUTES | flags);

      if (hImgSmall == IntPtr.Zero)
        return null;

      Icon icon = (Icon)Icon.FromHandle(shinfo.hIcon).Clone();
      Win32.DestroyIcon(shinfo.hIcon);
      return icon;
    }
  }
}

Sunday, August 11, 2013

“unknown CMAP subtable format” error when generating PDFs

Whenever I get an unusual exception being thrown by my application that I don’t know how to fix, I Google the error message which generally leads to some kind of explanation of what’s happening. But Google seems to have a hole in its knowledge regarding this “unknown CMAP subtable format” error I was getting. So I’ll try and fill that hole.

Our software uses XSLT to generate XSL:FO files that are then converted to PDF files using AltSoft’s XML2PDF engine. The error was occurring deep inside their assembly and the only clue I could get from looking at the call stack was that the problem was font related. My immediate suspicion was that the error was due to the user using a strange font in their input, but the fonts in use were fairly standard (Arial, Calibri).

I eventually figured out the problem was due to some of the particular characters being used in the input text. It seems the user had pasted some text from Word that contained some characters that weren’t available in the fonts used in the output. Cleaning up the user’s input text stopped the exception being thrown.

Saturday, January 28, 2012

Developer interview questions

A while back I had to interview some people for a developer role at work so came up with a few questions, combining a few from the web with some of my own. This is essentially a note to myself for next time I’m interviewing.

jQuery
What's a jQuery selector? How would you select an item by its ID? By its class?
Give some examples of JQuery UI effects and widgets and what they could be used for

.NET
What's an interface? Compare and contrast with an abstract class
How does memory management differ between .NET and a non-managed language? How can we make .NET behave more like a non-managed language?
What are generics? Why use List<> instead of ArrayList?
What's a virtual function? How does it relate to OOP?

Web
What is a RESTful web service? Why are they preferred to SOAP web services?
What are the common data formats returned by an AJAX web service call? Is one better than the other? What about if you wanted to call it from a fat client?
Name and describe several HTTP status codes
Name the various HTTP verbs and when they are used

General
Your application has a performance problem, how would you investigate the issue?
An error occurs in your web application but only in production and only happens occasionally, how do you go about tracking down the problem?
What are some of the issues around multi-threaded applications?
Discuss some ways of ensuring code quality remains high in a project

Thursday, September 09, 2010

Structured storage viewer

Before the advent of .NET, Windows development involved a lot of fiddling around with COM interfaces and trying to figure out HRESULT error codes. One prime example of this is the interfaces used to access structure storage. Structured storage is a strange beast itself, providing a way to stitch together composite files, sort of like a seriously complicated version of ZIP files. Of course this was a solution in search of a problem, it turns out ZIP files are pretty much adequate for most situations, which is probably why Office now uses them.

But these technologies have a habit of sticking around (I guess Windows will continue supporting structured storage for the rest of time or until Windows no longer exists, whichever comes sooner). So I was faced with writing some code that had to interact with structured storage. .NET wisely doesn’t have any support for it, so I was faced with dealing with the really horrible COM interfaces. And I was even thinking I’d have to write a little application to let me see inside these composite files, so I’d have a clue what was going on. But fortunately I discovered somebody had already done the job for me, and I finally get to the point of this post. If you need a structured storage viewer, download it from here. http://www.mitec.cz/ssv.html

Friday, April 02, 2010

Temporary file class for C#

Quite frequently I need to create a temporary file, do some processing on it, then delete it. In order to ensure the file gets deleted, I put the file deletion code in a try…finally, which got me thinking about writing a simple class that implements IDisposable to handle this scenario, allowing me to use using. It’s very simple, but here it is anyway.

  public class TemporaryFile : IDisposable
  {
    public TemporaryFile(string fileName)
    {
      this.fileName = fileName;
    }

    ~TemporaryFile()
    {
      DeleteFile();
    }

    public void Dispose()
    {
      DeleteFile();
      GC.SuppressFinalize(this);
    }

    private string fileName;
    public string FileName
    {
      get { return fileName;  }
    }

    private void DeleteFile()
    {
      if (File.Exists(fileName))
        File.Delete(fileName);
    }
  }

Friday, August 28, 2009

Installing and debugging a .NET service built in Visual Studio 2008

There seem to be several tutorials on the web on how to create a Windows service using .NET in Visual Studio 2005 and before but I was unable to find one for Visual Studio 2008, so thought I’d write my own since I got tripped up a couple of times when I tried to install it.

The first step is easy, create a new project using New Project/Windows Service. The next obvious thing to try and do is to build it and run it. You will then be presented with the following error -

Cannot start service from the command line or a debugger.  A Windows Service must first be installed (using installutil.exe) and then started with the ServerExplorer, Windows Services Administrative tool or the NET START command.

So then you fire up installutil from the command line passing the EXE’s full path as the only parameter. If you make my schoolboy error, you’ll be faced with the following error message -

Exception occurred while initializing the installation: System.BadImageFormatException: The format of the file 'WindowsService1.exe' is invalid.

This is because I ran installutil from the standard command prompt, rather than the .NET command prompt and it picked up installutil from the .NET Framework 1.1. So when I figured that out I ran the correct version of installutil and got the following error message -

No public installers with the RunInstallerAttribute.Yes attribute could be found in the C:\Source\dotNET2\WindowsService1\WindowsService1\bin\Debug\WindowsService1.exe assembly.

So the next thing to do is to add an installer to the service. This is achieved by right clicking on the service’s design surface and selecting ‘Add Installer’. after doing this and running installutil once again, the service should appear in the Services applet.

Finally, to debug it you’ll need to start it from the Services applet and then use the ‘Debug/Attach to Process…’ menu item in Visual Studio, making sure the ‘Show processes in all sessions’ checkbox is checked if the service is running under a different account to your own.

Sunday, August 09, 2009

Poor man's profiling

If you don't have access to a profiler or you can't be bothered to fire up your profiler to see where you've got performance problems, there's a pretty simple way to find performance bottlenecks in your code. Just keep breaking into your code and if a particular piece of code is causing problems, then chances are you will keep being taken to that piece of code.

Thursday, July 09, 2009

More on string.Concat vs the + operator in C#

A post of mine from 3 years ago about the performance differences between using string.Concat and the string class’s + operator got its first comment yesterday so I thought I’d flesh out what I said there to clarify what happens. First, here’s a little test program to show different ways to concatenate strings.

  class Program
  {
    static void Main(string[] args)
    {
      Console.WriteLine("a" + "b" + "c" + "d");
      Console.WriteLine(string.Concat("a", "b", "c", "d"));

      string a = "a";
      string b = "b";
      string c = "c";
      string d = "d";
      Console.WriteLine(string.Concat(a, b, c, d));
      Console.WriteLine(a + b + c + d);
    }
  }

So now lets look at the IL generated from that, using our old friend Reflector.

.method private hidebysig static void Main(string[] args) cil managed
{
    .entrypoint
    .maxstack 4
    .locals init (
        [0] string a,
        [1] string b,
        [2] string c,
        [3] string d)
    L_0000: nop 
    L_0001: ldstr "abcd"
    L_0006: call void [mscorlib]System.Console::WriteLine(string)
    L_000b: nop 
    L_000c: ldstr "a"
    L_0011: ldstr "b"
    L_0016: ldstr "c"
    L_001b: ldstr "d"
    L_0020: call string [mscorlib]System.String::Concat(string, string, string, string)
    L_0025: call void [mscorlib]System.Console::WriteLine(string)
    L_002a: nop 
    L_002b: ldstr "a"
    L_0030: stloc.0 
    L_0031: ldstr "b"
    L_0036: stloc.1 
    L_0037: ldstr "c"
    L_003c: stloc.2 
    L_003d: ldstr "d"
    L_0042: stloc.3 
    L_0043: ldloc.0 
    L_0044: ldloc.1 
    L_0045: ldloc.2 
    L_0046: ldloc.3 
    L_0047: call string [mscorlib]System.String::Concat(string, string, string, string)
    L_004c: call void [mscorlib]System.Console::WriteLine(string)
    L_0051: nop 
    L_0052: ldloc.0 
    L_0053: ldloc.1 
    L_0054: ldloc.2 
    L_0055: ldloc.3 
    L_0056: call string [mscorlib]System.String::Concat(string, string, string, string)
    L_005b: call void [mscorlib]System.Console::WriteLine(string)
    L_0060: nop 
    L_0061: ret 
}

OK, so looking at the first method where we concatenate string literals using the + operator and we can see the compiler helps us out by concatenating the strings at compile time, which is going to be as optimal as possible. The second example shows that the compiler doesn’t do this magic when we use string.Concat so string.Concat is actually slower in this scenario.

Now if we look at the next examples where we concatenate string variables, the generated IL is exactly the same! So the performance characteristics are likely to be somewhat similar to say the least. Things get more interesting when you get beyond 4 strings since there is no version of string.Concat that takes more than 4 parameters, so they have to be pushed into an array but the result is the same, the + operator generates the exact same code as string.Concat.

So I can’t see a scenario where you’d want to use string.Concat (unless you’re particularly fond of it) and if string concatenation performance is an issue, you probably should be using the StringBuilder class.

Tuesday, June 30, 2009

Improving the Local Search .NET call

Following on from my post about using Google Local Search from C#, I thought I’d try to improve it. Deserializing the JSON data ended up with some ugly typecasts and manipulation of Dictionarys. The first thing to notice is that the JavaScriptSerializer class has a Deserialize<T> method so all that is needed is a class to hold the returned data. Here’s a simple implementation of this.

  public class Results
  {
    public double lat;
    public double lng;
  }

  public class ResponseData
  {
    public Results[] results;
  }

  public class LocalSearchData
  {
    public ResponseData responseData;
  }

OK, I know, there’s a bit of a lack of OO encapsulation going on there but it seems like public fields with names matching the data returned from the JSON are required. They can be replaced with properties, but these must have getters and setters so this doesn’t really buy you much except to stop FxCop moaning at you.

Then the deserializing code looks much nicer

        LocalSearchData searchData = serializer.Deserialize<LocalSearchData>(response);
        latitude = searchData.responseData.results[0].lat;
        longitude = searchData.responseData.results[0].lng;

This still isn’t perfect. We have to use the same names as used in the JSON, which doesn’t really match up with .NET naming conventions and we have a class hierarchy that doesn’t really serve a purpose. It looks like the JavaScriptConverter class might help out here but that’s something to look at another day. Another alternative might be to just use these classes for moving the data into yet another class that has a better interface.

Saturday, May 30, 2009

Intercepting a HTTP call to modify its behaviour

Say you have some application that uses a HTTP call to get hold of some XML data. It could be a web service but might also be an ASHX generic handler, or any kind of server-side HTTP handling code. Say you want to change the behaviour of that code in some way but you don’t have access to the source code but can change the URL that the calling application uses. What to do?

This was my problem to solve. Actually I didn’t realise it was a problem until I thought of the solution, then thought it would be an exceedingly useful thing to do, and may well be useful in other scenarios. The basic idea is to create a generic handler that will replace the original handler and in the simplest case just pass the request onto the original handler and return the response from the original handler. The configuration of the calling app needs to be updated to use the new handler.

There may be other solutions, such as adding a HTTP module to the original handler, if it happens to be an ASP.NET application. This solution may impact performance since two HTTP calls will be made rather than just one, but I still quite like it.

Here’s the code for the ProcessRequest method, that obviously needs updating to make any changes to the response returned by the original handler. It also shows how to deal with POST data, if the call you’re intercepting is a POST call.

    public void ProcessRequest (HttpContext context) 
    {
      context.Response.ContentType = "text/xml";
      
      // create outgoing HTTP request
      HttpWebRequest req = (HttpWebRequest)WebRequest.Create(
        ConfigurationManager.AppSettings["messageHandlerUrl"]);
      req.Method = "POST";
      req.KeepAlive = false;
      req.ContentType = context.Request.ContentType;

      // get POST data from incoming request
      string parameters;
      using (StreamReader postReader = new StreamReader(context.Request.InputStream))
      {
        parameters = postReader.ReadToEnd();
      }

      // add POST data to outgoing request
      using (Stream stream = req.GetRequestStream())
      using (StreamWriter streamWriter = new StreamWriter(stream))
      {
        streamWriter.Write(parameters);
        streamWriter.Close();
      }
      
      // get response
      using (WebResponse resp = req.GetResponse())
      using (Stream respStream = resp.GetResponseStream())
      using (StreamReader reader = new StreamReader(respStream))
      {
        string response = reader.ReadToEnd();
        context.Response.Write(response);
      }
    }

Thursday, May 28, 2009

Saving a control’s image to a file

Saving a WinForms control’s image to a file, should be pretty straightforward. After all, there is a DrawToBitmap method that should do the trick, right? Well, not quite. Unfortunately DrawToBitmap draws the controls in reverse order, i.e. the top controls are drawn first. So first you need to reverse the z-order of the controls on the form and then reverse them again then after generating the image, something like the following

        InvertZOrderOfControls(formControl);
        using (Bitmap bitmap = new Bitmap(formControl.Width, formControl.Height))
        {
          formControl.DrawToBitmap(bitmap, new Rectangle(0, 0, formControl.Width, formControl.Height));
          bitmap.Save(outputFile, ImageFormat.Jpeg);
        }
        InvertZOrderOfControls(formControl);

Ah, but what about the implementation of InvertZOrderOfControls? You can find that here.

Even after that frigging around, the saved image may not be perfect. The output produced is dependant on the underlying operating system. Vista and XP produce reasonably accurate output, but Server 2003 doesn’t look too good.

Monday, May 11, 2009

A generic error occurred in GDI+ when saving an image

This has to be one of the most useless error message I’ve ever encountered in the .NET framework. It seems that pretty much any problem that occurs when using Image.Save will produce this error message. Looking at the code in Reflector, the error is returned from the GDI+ function GdipSaveImageToFile. For me the solution was pretty simple, the folder I was trying to save my image to didn’t actually exist but it took some head scratching before I realised.

Saturday, May 02, 2009

A simple WinForms numeric edit control

There are plenty of controls out there that will allow only numeric entry but they may not meet your needs. If you don’t want the up/down buttons, the built-in NumericUpDown control won’t be of use and using one of those huge libraries just for their numeric control may be overkill. If that describes your position, this uber-simple control may fit the bill.

  public class NumberControl : TextBox
  {
    /// <summary>
    /// Creates a new <see cref="NumberControl"/> instance.
    /// </summary>
    public NumberControl()
    {
      TextAlign = HorizontalAlignment.Right;
    }

    /// <summary>
    /// Triggered when a key is pressed. Swallows all keys except for digits.
    /// </summary>
    protected override void OnKeyPress(KeyPressEventArgs e)
    {
      base.OnKeyPress(e);
      string decimalSeparator = CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator;
      if (e.KeyChar.ToString() == decimalSeparator)
      {
        if (Text.IndexOf(decimalSeparator) > -1)
          e.Handled = true;
      }
      else if (!char.IsDigit(e.KeyChar) && !char.IsControl(e.KeyChar))
      {
        e.Handled = true;
      }
    }
  }

Tuesday, March 17, 2009

Whatever happened to NDoc?

NDoc was one of my favourite tools for .NET. Document your assemblies with the .NET XML documentation tags, point NDoc at them and out comes a help file. It was simple to use but was also powerful enough to customize the output in most ways you’d want.

Go to the linked website and you’ll see not much has happened on the NDoc project since 2005. Unfortunately support for .NET 2 was never completed before the original author decided to give up on the project and it looks like nobody has picked up the baton to develop it further. This is understandable to an extent. After all Microsoft have come out with Sandcastle which essentially does the same thing as NDoc. But Sandcastle is difficult to love. It has no user interface and builds take forever compared to NDoc.

The user interface problem can be solved by using Sandcastle Help File Builder, which does a nice job of looking like NDoc, but is still hampered by the underlying Sandcastle technology. After much frigging around I’m still unable to figure out how to add custom HTML into my documentation (for Google Analytics and the like) on a per project basis. I can do it globally by messing with the templates but this means I have to modify the templates for each build of a particular project, which is not ideal.

Perhaps I’m missing something, but it seems sad that 4 years since development on NDoc stopped, we still don’t have something as easy to use or as fast, even with the might of Microsoft behind it. I’m not surprised the original author decided to stop working on it, apparently he was getting threatened because his support for .NET 2 wasn’t coming along fast enough… And I’m sure the thought of trying to compete with Microsoft didn’t encourage his efforts either. But Microsoft have failed to deliver IMHO so I’m still missing NDoc after all this time.

Friday, February 27, 2009

Copying a stream to another stream

It’s obvious that the ability to copy the contents of one stream to another is something that you’re likely to want to do fairly regularly. I vaguely recall that this will be added to some version of the .NET Framework but until that time, here’s a simple implementation that should do the trick. It could easily be converted into an extension method so it plays better in the .NET 3 world.

    /// <summary>
    /// Copies a stream to another stream
    /// </summary>
    /// <param name="copyFrom">The stream to copy from</param>
    /// <param name="copyTo">The stream to copy to</param>
    public static void CopyTo(Stream copyFrom, Stream copyTo)
    {
      const int buffSize = 128;
      byte[] buff = new byte[buffSize];
      int count;
      do
      {
        count = copyFrom.Read(buff, 0, buffSize);
        copyTo.Write(buff, 0, count);
      }
      while (count > 0);
    }

Saturday, February 07, 2009

WPF ASCII grid part 2

This is the second in a series where I try to learn how to develop WPF apps. The first part is here.

So my next step was to put all the ASCII grid code into a custom control. My first attempt was to inherit from Grid and add the logic to create the cells in the inherited class. The problem with this approach was that the grid’s row and column definitions could be edited in Visual Studio which I didn’t want. So I decided to inherit from Panel and add the grid as a child control. When I did that, running the application showed up nothing at all. I finally realised that was the wrong approach, since the Panel class is designed to allow the end user to add their own child controls. I guess the WPF runtime is looking at the XAML to see which children should be added to the panel and there aren’t any. So finally I inherited from Control and then had to figure out how to add the grid as a child. Control doesn’t have a Children property so it’s not obvious how to add your own child controls. But it turns out it’s pretty easy to do. You just have to override VisualChildrenCount and GetVisualChild as shown below.

  public class AsciiGrid : Control
  {
    static AsciiGrid()
    {
      DefaultStyleKeyProperty.OverrideMetadata(typeof(AsciiGrid), new FrameworkPropertyMetadata(typeof(AsciiGrid)));
    }

    private Grid grid;
    public AsciiGrid() : base()
    {
      grid = new Grid();

      const int width = 16;
      const int height = 16;
      for (int x = 0; x < width; x++)
      {
        grid.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(1, GridUnitType.Star), });
      }
      for (int y = 0; y < height; y++)
      {
        grid.RowDefinitions.Add(new RowDefinition() { Height = new GridLength(1, GridUnitType.Star), });
      }
      for (int x = 0; x < width; x++)
      {
        for (int y = 0; y < height / 2; y++)
        {
          int asciiValue = ((y * width) + (x + 1));

          // number
          TextBlock rect = new TextBlock();
          rect.Text = asciiValue.ToString();
          rect.SetValue(Grid.RowProperty, y * 2);
          rect.SetValue(Grid.ColumnProperty, x);
          grid.Children.Add(rect);

          // ASCII value
          rect = new TextBlock();
          rect.Text = Convert.ToChar(asciiValue).ToString();
          rect.SetValue(Grid.RowProperty, (y * 2) + 1);
          rect.SetValue(Grid.ColumnProperty, x);
          grid.Children.Add(rect);
        }
      }
    }

    protected override int VisualChildrenCount
    {
      get
      {
        return 1;
      }
    }

    protected override Visual GetVisualChild(int index)
    {
      return grid;
    }
  }
So I now have a standalone control in my application. The application looks exactly as it did before but I’ve now got an exceedingly useful re-usable ASCII grid control. OK, maybe not so useful, but this is a learning experience, so cut me some slack. The only thing to note is the changes required to the XAML to host the control, which looks like this.
<Window x:Class="Ascii.AsciiWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:Ascii="clr-namespace:Ascii"    
    Title="Ascii" Height="370" Width="413" Loaded="Window_Loaded">
    <Ascii:AsciiGrid x:Name="m_Grid">
    </Ascii:AsciiGrid>
</Window>

WPF ASCII grid part 1

Ascii

I thought it was about time I learned about WPF so thought I’d start with a very simple application, a grid showing the ASCII characters. It’s kind of pointless at the moment since you can find this information on the web pretty easily but I think I can make it somewhat more powerful and in the process learn more about WPF. This is what I’d like to add in the future and will hopefully blog about as I implement them

          • Turn the grid into a control
          • Show the extended ASCII characters
          • Make it look much sexier
          • Let the user choose the font
          • Let the user change the code page

The code currently looks like this. It’s all pretty straighforward. The first thing to note is the GridUnitType.Star enumerated value which means each column and row will be spaced equally in the window.

The other thing to note is the weird way the text blocks are assigned to the correct cells of the grid. It doesn’t seem a natural way to do it, but I guess once you know that’s how it’s done, it’s pretty straightforward.

    public AsciiWindow()
    {
      InitializeComponent();
      BindGrid();
    }

    private void BindGrid() 
    { 
      const int width = 16;
      const int height = 16;
      for (int x = 0; x < width; x++) 
      { 
        m_Grid.ColumnDefinitions.Add(new ColumnDefinition() 
        { Width = new GridLength(1, GridUnitType.Star), }); 
      }
      for (int y = 0; y < height; y++) 
      { m_Grid.RowDefinitions.Add(new RowDefinition() 
        { Height = new GridLength(1, GridUnitType.Star), }); 
      }
      for (int x = 0; x < width; x++) 
      {
        for (int y = 0; y < height/2; y++) 
        {  
          int asciiValue = ((y*width)+(x+1));

          // number
          TextBlock rect = new TextBlock();
          rect.Text = asciiValue.ToString();
          rect.SetValue(Grid.RowProperty, y*2); 
          rect.SetValue(Grid.ColumnProperty, x); 
          m_Grid.Children.Add(rect); 

          // ASCII value
          rect = new TextBlock();
          rect.Text = Convert.ToChar(asciiValue).ToString();
          rect.SetValue(Grid.RowProperty, (y * 2)+1);
          rect.SetValue(Grid.ColumnProperty, x);
          m_Grid.Children.Add(rect); 
        } 
      } 
    }

Read part 2

Wednesday, February 04, 2009

Bugs = complexity

Many moons ago I discovered a bug in some software I use on a fairly regular basis (I won’t tell you which software since it isn’t relevant to the story and I don’t want this to appear to be a critique of the company or their development process, though you can probably figure out who it is if you look round the rest of this site). The application allows you to write server scripts in JScript.NET. It also does some validation of these scripts but in certain circumstances this validation incorrectly flags up problems with scripts that aren’t actually problems. It was a fairly innocuous bug so I reported it but didn’t push for it to be fixed.

Fast forward a year or so and a new version of the software comes out with a new feature that validates your scripts when you try to deploy a project to the server. Generally a useful feature except the previous bug is still there. Meaning I now can’t deploy perfectly valid projects due to the interaction of the previous bug with this new feature. So a minor unfixed bug has blown up into a major issue.

Which got me thinking. The kind of bugs that don’t get fixed are these kind of things. They only occur in particular rare scenarios. If they happened all the time, the chances are they would get fixed, if they are serious enough. But they do add complexity to the product and testing. No longer can we assume doing A will cause B to happen. Most of the time it will be true but occasionally doing A will cause C to happen. So any testing of new features will have to take this into account. In fact, testing of any new feature will have to take into account any unfixed bugs that may impact the new functionality.

There are many reasons for trying to fix as many bugs as possible (keeping customers happy, trying to fight the constant entropy inherent in software development), may I add this to the list?