Thumbnail

Before I was a .NET developer I wrote almost exclusively in C++ for Microsoft Windows. I did that for well over a decade, which was long enough to build up a fairly sizeable collection of classes and libraries for myself. Later, when .NET came along, I ported parts of that old C++ code to .NET using embedded COM and PInvoke calls. That was the “best practice” at the time. Using that approach allowed me to extend the life of my old code right up until .NET Core came along.

.NET Core however, changed the rules a bit. You see, as any .NET developer will tell you, .NET Core is intended to run on non Windows platforms. That means, the tried and true PInvoke mechanism are no longer appropriate. Since I now make my living writing portable .NET Core applications, websites and libraries, that means some of the code I’ve relied on for so long is now at the end of it’s useful life.

But, that doesn’t mean I have to simply throw it all in the trash! I have a blog now, which means I can write articles about all my old code!

*coughs*

Well, seriously, some of my older code still works well enough – as long as it runs on the Windows O/S. I figure, a tether to Windows isn’t great but it’s also not a death sentence either. After all, there’s still a ton of .NET code written every day that will probably never run outside of Windows.

So, I thought I might take the opportunity the cover a class I once wrote to generate thumbnail images. The code was originally written in C++, using raw COM calls with references to SDK structures and data types. It was later ported to C# and then infrequently tweaked as things changed, over time, in the O/S. The code still compiles and works and I still use it on several desktop applications that are written in .NET.

The class itself has had several names over the years but I just call it “Thumbnail” now. It uses PInvoke and COM calls to integrate with the Windows Shell for the purposes of generating thumbnail images. Doing things that way means that the class uses almost the exact same mechanism for generating thumbnail images as Windows Explore does. That means, if you use this class you won’t need any additional 3rd party libraries to handle the thumbnail generation. Very handy.

There is one caveat though. Because the class is, in effect, piggy backing off the Windows Shell, it means that if Windows can’t create a thumbnail for a particular file type, then this class won’t be able to either. The implications of what I just said are, if you want a thumbnail image of (for instance), a .FLV file (which is a flash video format used on the web), then you’ll need to make sure there’s a CODEC for that file type registered on your machine. For a desktop environment that’s not usually an issue but, for a server environment, you might get some push back from the admin’s when you explain the need to load 3rd party CODECS onto the server, in order to generate thumbnails.

That’s a battle I’ll leave to you. Just keep in mind, this approach is somewhat better suited to a desktop environment than a sever environment.

 

The Code

As I mentioned before, the class is called “Thumbnail”. I’ll publish a somewhat trimmed down version in this article to keep the size of the listing down. I’ll also link to the original code, which will have tons and tons of comments that have built up over the years.

Here is the code listing. I’ll start the description afterwards.

 

The internals

Let’s just start at the top of the class and work our way to the bottom.

A best practice, at the time I originally ported this code from C++, was to group all PInvoke “stuff” into an embedded class named “NativeMethods”. I followed that practice, so, there is a NativeMethods class in the code. Much of what’s in this embedded class is completely beyond the scope of this article and frankly, not very interesting by itself. What’s important is to know that the definition of the various COM interfaces and low-level SDK structs and types, are here, in the NativeMethods class.

The only public method on the Thumbnail class is called Create. It accepts the following parameters:

  • A file path, which should point to the file we want to make a thumbnail of.
  • A width parameter, for the width of the thumbnail image.
  • A height parameter, for the height of the thumbnail image.
  • An ImageFormat enumeration, for the format of the thumbnail image.
  • A bool for enabling an overlay icon.

The purpose of the method is, obviously, to generate a thumbnail image. It does that by trying several different strategies. If one of the strategies fails it tries another, continuing on until at least one of them produces a thumbnail image. The method calls our GenerateFromShell method first, since that’s our best bet for creating a good thumbnail. For some older O/S flavors though, that approach won’t work, so, if it fails, we then call either our GenerateFromFileTypeNT (if we’re running on Windows NT or later), or GenerateFromFileTypeXP (if we’re running on an older OS). If either of those two methods fails, we fallback again and call our GenerateFromNothing method, which is pretty much guaranteed to create something for a thumbnail – even if it’s not the quality we would have gotten from any of the other approaches. This way, no matter what happens, we at least generate an image of the specified width, height, and type – no matter what.

 

There are four private methods that each try a slightly different approach to generating a thumbnail image. The first, named GenerateFromNothing, is used as a last resort, after everything else has failed. We start by creating a new bitmap object, using the height and width that were passed as parameters. Once that’s done we create a Graphics object from that bitmap and use it to fill the background with white. Then we create a nice looking font and, using the extension of the file, we draw that file extension in the middle of the image to generate a sort of “bare bones” thumbnail image. Obviously, this isn’t what most people want when they ask for a thumbnail but I wanted this class to always return *something*, even if it was just a white square with the file extension written on it. That’s what this method handles. The method ends by calling a custom extension method named Convert, to convert the image to the type specified by the ImageFormat enumeration (we’ll cover the internals of our ImageExtensions class at the end of the article).

 

The next method is named GenerateFromFileTypeNT. This is the second strategy we try, when running on a newer OS, when our first thumbnail strategy has failed us. We start this method by calling the NativeMethods.SHGetFileInfo method, which should populate a NativeMethods.SHFILEINFO struct for us. That structure contains information about the file that we want to generate a thumbnail for – specifically the index of the system icon list. Next we call NativeMethods.SHGetImageList to actually retrieve the system image list for the file. Afterwards we check the return code and throw an exception of there was a problem. That’s a pattern we’ll follow throughout the rest of this code listing.

Once we have the image list, and the proper index, we can retrieve the icon for the file (which is actually the thumbnail we’re after). At this point we have a handle to a Windows icon, but we need to convert it to an image in the format we’re looking for. So, we create a managed icon using the handle we just got from the OS. Then we create a bitmap sized for a thumbnail. Then we fill the background of the icon, just so we start from a white square, versus random bits. Finally, we draw the managed icon centered into our bitmap, thereby creating our thumbnail image. The method ends by calling a custom extension method named Convert, to convert the bitmap image to the type specified by the ImageFormat enumeration. Notice the finally block, where we specifically cleanup the COM object as and icon handles that were created during the method.

 

The next private method is named GenerateFromFileTypeXP. This is the second strategy we try, when running on an older OS, when our first thumbnail strategy has failed us. We start by calling the NativeMethods.SHGetFileInfo method, just like we did in our GenerateFromFileTypeNT method – but this time we ask for the icon itself (the largest version we can get). There difference here, between this approach and what we did in GenerateFromFileTypeNT, represents an evolution of the underlying OS. After Windows NT, Microsoft just made some changes in the way they exposed the icons for files. After we get the icon here, we can directly use it so we create a managed copy of the icon, then we create the bitmap object for the thumbnail, when we create a graphics object using that managed bitmap, then we fill the background and draw the icon, centered into the image. The method ends by calling a custom extension method named Convert, to convert the bitmap image to the type specified by the ImageFormat enumeration. Notice the finally block, where we (again) specifically cleanup the COM object as and icon handles that were created during the method.

 

The final private method in our Thumbnail class is called GenerateFromShell. This represents our first strategy for generating thumbnail images. This is the approach that works best for most modern flavors of Windows. It doesn’t always work for older versions of Windows, which is why we have a mechanism built into our class to try the secondary strategies if this one fails.

We start the method by getting a reference to the desktop, which is the root object from which we’ll reference pretty much everything else in this method. Next we use the desktop object to parse the folder that contains the file we want to generate a thumbnail from. “Parsing” in this sense doesn’t mean we actually open anything and try to process it’s contents. Parsing is more of a COM term used to imply that we’ll ask the OS for information about an object.

Next we check that the COM call didn’t fail (again, following our error checking pattern).

The output of the parsing operation gave us a PIDL (which is just an opaque object that COM uses to keep track of things). We use that PIDL in our next step to bind to the underlying folder object using the BindToObject method call, on the desktop object.

Afterwards, we call ParseDisplayName to parse again (yes, the two calls are needed, and yes they must be two calls). The first parsing operation gave us a PIDL for the folder that houses the file we want to generate a thumbnail for. The second parsing operation gives us a PIDL for the file object itself.

After we get the PIDL’s, we call GetUIObjectOf, on the folder object, to extract the image list for the file object. That object comes back to us as an IUnknown reference, which is sort of the COM equivalent of an object reference, so we have to perform the cast to an NativeMethods.IExtractImage type, in order to actually extract the image we want, from the image list.

Next we call GetLocation on the image extractor object, to locate the image we want. Then, finally, we actually extract the thumbnail image for our file. The result of all that work is a bitmap handlethat points to a bitmap containing our thumbnail – but, the OS owns that bitmap so we’ll need to copy it for our purposes. We do that by first creating an Image object from that low-level bitmap handle. Then, once we have a managed copy of the bitmap to work with, we can perform the rest of what we need to do.

So, once thing this method does is potentially create an overlay on the thumbnail. That used to be a big deal for me back when I wrote a lot of Windows shell extensions, until I figured out that .NET is actually a terrible language choice for writing Windows shell extensions. Anyway, the code is still here because I actually still use it for other things now. Let’s walk through that part of the method …

Assuming the enableTypeOverlay flag is TRUE, we call SHGetFileInfo on the file path in order to get an icon for the file type. That’s not a thumbnail image. It’s just an icon for the file type itself. You’ve seen these icons in Windows explorer, with different icons for different types of files. Once we get that icon, we can draw it in the lower corner of our thumbnail so that we end up with a thumbnail that not only depicts the contents of the file, but also the type of the file – all within the same thumbnail image.

Yeah, so, if you don’t want that to happen, just leave the enableTypeOverlay set to false.

The method ends like all the others, by calling a custom extension method named Convert, to convert the bitmap image to the type specified by the ImageFormat enumeration. Notice the finally block, where we specifically cleanup the COM object as and icon handles that were created during the method.

 

So, that’s pretty much it for the Thumbnail class. The code uses several different strategies because it had to exists for a long time with several different flavors of Windows. If you don’t need the older strategies feel free to remove them.

 

Let’s look at the Convert method, on the ImageExtension class now.

 

This method takes an Image object and converts the contents of that object into whatever other format is specified by the ImageFormat parameter.

We start by creating a memory stream object but notice that we don’t put that object into a using block. That’s because once an image is created from a stream, the image essentially owns that stream and will stage a million pixel march on Washington if anyone tries to close the stream afterwards. I’m still not sure I know why that behavior exists, but it does.

So, we take the memory stream and “save” the image into it, using the format passed in as a parameter. Then, we go back to the beginning of the stream and we return a copy of that image, using the Image.FromStream call. The result, is a copy of the image in whatever format was specified by the ImageFormat parameter.

Final Thoughts

The code I’ve presented here started out, years ago, as a Windows C++ class. It originally used a combination of COM and SDK calls to generate thumbnails and did that fairly well. Later, the code was ported to .NET. Then, still later, it was slowly modified to support various changes in the Windows OS, as they happened. Today, the code is very dated but still usable to anyone who wants to generate thumbnail images while running on a Windows machine, and do so without having to pull in a bunch of 3rd party libraries.

There are caveats to using the class, which I covered at the beginning of the article. If you can live with those considerations, and you need quick, decent thumbnails for your Windows app, then this class might come in handy for you.

 

I no longer have this code published on NUGET. I do, however, have a link to a zip file containing the two source files here:

ThumbnailSource

 

Have fun! :o)

 

Image courtesy of PixaBay