I’ve written my own icon file reader and icon writer in c# (Windows Forms – it reads the icons into System.Drawing.Icon instances), and since the samples I found on it were sparse and mostly buggy, I’m sharing mine.
Again, the source, for this and a whole bunch of other stuff, is here: RomyView.zip
Firstly, don’t trust all code you find online to actually do the job properly. My code is based in principle on an explanation I found a while back on Raymond Chen’s blog, The Old New Thing. (Sorry, I don’t have the exact URL.) I have read his blog every day for several years, and it often contains extremely useful snippets of code. They’re all in C or C++ and my icon reader code looks nothing like his samples, but the reason I say it is based on his explanation is that he makes it very clear, when icons are in PNG format, which supports a max size of 256×256, since the dimensions are each stored as a byte in c#, the maximum of which can be 255, the magic value of zero is used to indicate 256. Before I read his article, I had downloaded and attempted to use the code from two CodeProject articles, both of which crashed when they encountered 256×256 PNG icons.
Though some of my code may well depend on other parts of my solution (especially async extension methods), there are only three files relevant in my solution. I’m not going to explain this in any detail – that shouldn’t be necessary. Firstly, I define the structures necessary:
A quirk of my implementation (which I shall explain more further on) causes my icons to “lose” the original bit depth. Thus in my reader, the Images property exposed is a collection of a simple interface type shown below. This interface stores the Icon itself, and a variable used to store the bit depth that was lost.
Then the actual code of my IconFileReader:
That’s it. Nothing complicated there.
One thing I said I would expand on is the IIconData interface, and why it is needed. What I found, after reading the icon data into a stream, is that it would throw an exception if I tried to instantiate an Icon from the contents of the stream. No matter what I tried, it would fail. But, it did allow me to instantiate an Image. Once it’s an image, it’s then possible to use the Image.GetHIcon method to get an Icon instance, but at that point, though it looks identical to the original icon, the bit depth is lost. What we get is actually a 32 bit icon that looks like the original. (At that point, the icon obtained by GetHIcon must me destroyed with the DestroyIcon Windows API function. We use a copy of that icon.)
But having the interface is quite useful. From the viewer of my application, I created a derived interface, adding a modified flag, which then allowed me to add UI controls to “page” back and forth through the icon images, modifying the separate images, and saving them to a new icon afterwards. That is beyond he scope of this article, but it is in the code if you download the zip file.