Add my own icon overlays

Introduction

The requirement: Add icon overlays to a folder when it is a Python package

Discussion

Things like icon overlays (those little bitmaps which appear in the bottom left-hand
corner of icons, like the shortcut arrow) belong to the area of Windows programming known
as Shell Extensions. (It's never bothered me particularly, but I imagine it confuses people
coming from a *nix background where the shell is everything except the Windowing
subsystem to discover that, in Windows, Shell programming is only the Windowing
subsystem!)

The whole of the Shell API appears to have been designed in some kind of isolation
from the rest of the Windows API. There are a few things which you can do either way,
but most things you can only do using the Shell functionality. And icon overlays are
one such thing. But if you look at a few examples of how to set them up, you'd be
excused for backing away pale and trembling. Fortunately, though, once you cut through
the COM-related verbiage and the C++/ATL clutter which tends to obscure the real
code in the sort of examples you find online, the basic idea is quite simple. And, thanks to
the sterling work of the pywin32 development team, not hard to implement under Python.

In fact, setting up a shell extension comes down to a few easy* steps:

Create a class implementing the methods which the shell extension requires.

Register this class as a COM Server and, probably, force explorer to restart.

Make use of your Shell extension

*For some definition of easy, naturally!

Fundamentally, shell extensions are a callback mechanism. You set up a series
of callback methods with a class according to the MS docs, register the class as
a COM Server of the right type, and link the COM Server to the shell extension within the registry.
When the shell finds it needs, say, an overlay handler, it scans the list of
handlers, finds yours, instantiates your COM server and calls the methods you've
implemented. Simple, no?

Notes

The GUID assigned to _reg_clsid_ should of course be generated specifically
by you. You can use pythoncom.CreateGuid for this. Likewise the name and
descriptions are obviously settable. The _public_methods_ and _com_interfaces_
should be left alone.

For the purposes of demonstration, I'm using an overlay icon from the TortoiseHg
set. If you don't have that installed you can get it from
here
or just use something else.

When the COM server represented by this class is started up,
GetOverlayInfo is called to return the one icon which it will
be using for overlays [*],
and GetPriority is called to get some kind of indication
of priority between cooperating icon overlay handlers. This won't help your
handler to beat someone else's but if you're the the only one interested
in a particular file type and you have several handlers you can use this
to negotiate between them somewhat.

Now, each time explorer wants to display a file or folder, it calls
the IsMemberOf method of every registered icon overlay handler to see
if it's interested in overlaying the file icon. This means that a
handler which is not interested in a file should return E_FAIL as fast
as it can. (And shouldn't spend too long returning S_OK either). Based
on that return, explorer will overlay your defined icon on the file's
default icon.

* I'm using an .ico file, so the second parameter
representing position is zero, and the third parameter indicates that an
icon file is being used. To use an .exe or a .dll containing icons, pass
that filename as the first parameter, indicate which icon to select by
the second parameter, and pass shellcon.ISIOI_ICONINDEX as the third
parameter.