Question

Windows shell extension with C# and Shell Namespace Extension. C#. C++, MFC, AT—what to use? ask some of my questions, but it (and the answers) are over two years old. I'm using Visual Studio 2013 with .NET 4.5[.1]. I've also read the Guidance for Implementing In-Process Extensions which among other concerns lists interactions with the Runtime Callback Wrapper as a reason for not using .NET for shell extensions.

My thought was to implement the actual shell interfaces in C++/CLI as a native C++ class, but to pass off almost all the real work to .NET. Would this solve many of the problems (such as RCW concerns) cited in the MSDN article?

Code might be along the lines of:

namespace Managed { // C#
   public interface IShellFolder { … mimic native IShellFolder in C# … }
}

#include <shobjidl.h>
class CShellFolder : public IShellFolder // C++/CLI
{
   private: gcroot<Managed::IShellFolder> m_shellFolder;
};
Was it helpful?

Solution

Hmya, these problems are real enough, it reads like a very old sampling of the support calls that Microsoft got when .NET programmers started writing shell extensions. And of course they did, .NET makes it a lot easier to get them going. Lots of the nasty COM plumbing is nicely hidden by the CLR to the point that it is (almost) entirely invisible. These problems are not exclusive to .NET code, STA re-entrancy and interface marshaling are very much an issue in native code as well. And easy enough to avoid, as long as you know what you are doing. Which is certainly a problem in .NET, you can't easily find out what it is doing. It makes it too easy.

They don't even mention the biggest problems, big hint that this is old, the CLR version injection problem is a very hard one to solve. For one, if another shell extension also was written in .NET, it will load the CLR into Explorer. If this extension uses an older version than you require then your extension will fail to load, going down in flames on trying to run on a CLR that can't even load your assemblies. Work was done in CLR v4 to avoid this but it isn't perfect, an old one that loads before all the others still induces the failure.

And it is not just limited to Explorer, your shell extension gets injected in any process when it uses a common Windows feature like OpenFileDialog. Writing a DLL that can be injected into an arbitrary process without ever causing trouble in that process is something that needs to be approached with a very strong Hippocratic oath, though shalt do no harm first. Dragging in the entire CLR and jitter is a very un-Greek thing to do.

These kind of failures are extremely hard to diagnose, Explorer doesn't give a peep when it can't load your extension. And programs that die from injected code never give anything to look at. You'll get a call from a customer and he'll tell you "it doesn't work, help me". Or worse, he'll call the owner of the program that was killed by your extension. That's not the kind of support phone call that anybody ever wants to answer.

And just like you, Microsoft also doesn't want to take the support call and have to explain these kind of COM details to a programmer that never remotely heard of it. And they don't, writing shell extensions in .NET is officially unsupported. You can forge ahead and ignore the ominous wording, but if you hit a wall then you can't call Microsoft for help. Don't count on much help from SO either btw, shell extensions are an obscure topic.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top