Windows Forms: October 2006 Archives

In an earlier article (Accessing Embedded Resources using GetManifestResourceStream) I showed how to retrieve resources from an Assembly. In that particular case, the executing Assembly contained the embedded resource that we wanted to retrieve. What happens when the embedded resource is not in the executing Assembly? When it's located in a different C# Assembly, in a library built for controls or standalone classes? You can still do it, but you can't use GetExecutingAssembly.

In my case, I am building a library containing some Image controls, called CrystalUtils. This particular library contains a C# class for displaying Thumbnail images. When the control is used within the Visual Studio designer, I want to display a default thumbnail image. To access the default image, I have a class called CrystalTools which contains a static method called GetDefaultImage:

public class CrystalTools
{
  static private Bitmap _defaultImage = null;
  static private Image _defaultThumbnailImage = null;
  static public string DefaultImageName = 
        "CrystalUtils.resources.DefaultImage.bmp";

  static public Image GetManifestImage(Assembly theAssembly,
      string imageResourceName)
  {
    if (theAssembly != null)
    {
      Stream _imageStream;
      _imageStream = theAssembly.GetManifestResourceStream(
            imageResourceName);
      return new Bitmap(_imageStream);
    }

    return null;
  }

  static public Image GetDefaultImage(Assembly theAssembly)
  {
    if (_defaultImage == null)
      _defaultImage = (Bitmap)GetManifestImage(theAssembly, 
            DefaultImageName);

    return _defaultImage;
  }

GetDefaultImage takes an Assembly object as the first parameter. The Assembly object you pass cannot be the executable, you need to get the Assembly object that the caller knows contains the desired resource. In this case, a non-static object called CrystalFlipper is calling default image:

Image theImage = CrystalTools.GetDefaultImage(
    Assembly.GetAssembly(typeof(CrystalFlipper)));

Assembly.GetAssembly takes a Type parameter. Each C# class has its own unique type identifier. The typeof operator returns the correct type for the class CrystalFlipper. When I first tried this, I called it this way:

Image theImage = CrystalTools.GetDefaultImage(
    Assembly.GetAssembly(GetType()));

GetType() did work in my test application just fine. When I used it in a real application, I derived a class from CrystalFlipper and overrode some virtual methods. At that point, GetDefaultImage threw an exception. GetType() returned the type of the child class, not CrystalFlipper. While I could see that behavior working in different situations, in this case the typeof() operator gave me access to the same Assembly that my thumbnail classes originated from.