If you are thinking about writing Shell extension handles in .Net, please think again.
(From Jesse Kaplan, one of the CLR Program Manager.)
Unfortunately unmanaged C++ is really the only way to go here.
Writing in-process shell extensions in managed code is actually a very dangerous thing to do because it has the effect of injecting your managed code (and the .NET Framework) into every application on the machine that has a file open dialog.
The problems occur because only one version of the .NET Framework can be loaded in a process at any given time (other shared components such as java and msxml have the same property and thus the same restriction).
If you write your shell extension using the 2.0 .NET Framework and an application built with the 1.1 .NET Framework uses a file open dialog, your shell extension will fail because it can not run on an earlier version. Things can get even worse if your shell-extension manages to get loaded in a process before another applications managed code does: your extension may force an existing application onto a different runtime version than the one it was expecting and cause it to fail.
Because of these problems we strongly recomend against using any single-instance-per-process runtime or library (such as the .NET Framework, java, or msxml) in an in-process shell extension.