Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Windows shell extension with C#

I was wanting to write a simple windows shell extension to add to the context menu, and C# is the language I most use these days. Is it a decent choice for a shell extension? Are the interfaces easy to get to with it? Is there additional overhead that causes the menu to be slower to pop up?

Any one have good pointers for getting started?

like image 684
Pete McKinney Avatar asked Feb 03 '10 18:02

Pete McKinney


People also ask

What is Windows shell extension?

Shell extensions can be represented as individual plug-ins to Windows Explorer. They can be used to add a new tab to the Properties window, change a file preview, and do other things. Before taking any action, the Shell calls registered extension handlers to customize this action.

What is shell extensions in Foxit Reader?

Shell Extension enables you to see a preview of the current PDF view, thumbnails of PDF files in windows File Explorer and preview a PDF attachment in Microsoft Outlook 2007 above. By default, the Shell Extension got installed with the main program.

What is ShellEx in registry?

The ShellEx key is for shell extensions, these are COM objects and there are various extension points in the shell and each type is a subkey of ShellEx. ShellEx\ContextMenuHandlers is the shell extension version of the plain Shell key. The different types of shell extensions are listed here.


2 Answers

A Raymond's post: Do not write in-process shell extensions in managed code.


A recent follow-up: Now that version 4 of the .NET Framework supports in-process side-by-side runtimes, is it now okay to write shell extensions in managed code?

The bottom line is, no, it is not okay:

The Guidance for implementing in-process extensions has been revised, and it continues the recommendation against writing shell extensions and Internet Explorer extensions (and other types of in-process extensions) in managed code, even if you're using version 4 or higher.

like image 92
GSerg Avatar answered Oct 05 '22 21:10

GSerg


Guidance for Implementing In-Process Extensions

Version Conflicts

A version conflict can arise through a runtime that does not support the loading of multiple runtime versions within a single process. Versions of the CLR prior to version 4.0 fall into this category. If the loading of one version of a runtime precludes the loading of other versions of that same runtime, this can create a conflict if the host application or another in-process extension uses a conflicting version. In the case of a version conflict with another in-process extension, the conflict can be difficult to reproduce because the failure requires the right conflicting extensions and the failure mode depends on the order in which the conflicting extensions are loaded.

Consider an in-process extension written using a version of the CLR prior to version 4.0. Every application on the computer that uses a file Open dialog box could potentially have the dialog's managed code and its attendant CLR dependency loaded into the application's process. The application or extension that is first to load a pre-4.0 version of the CLR into the application's process restricts which versions of the CLR can be used subsequently by that process. If a managed application with an Open dialog box is built on a conflicting version of the CLR, then the extension could fail to run correctly and could cause failures in the application. Conversely, if the extension is the first to load in a process and a conflicting version of managed code tries to launch after that (perhaps a managed application or a running application loads the CLR on demand), the operation fails. To the user, it appears that some features of the application randomly stop working, or the application mysteriously crashes.

Note that versions of the CLR equal to or later than version 4.0 are not generally susceptible to the versioning problem because they are designed to coexist with each other and with most pre-4.0 versions of the CLR (with the exception of version 1.0, which cannot coexist with other versions). However, issues other than version conflicts can arise as discussed in the remainder of this topic.

Performance Issues

Performance issues can arise with runtimes that impose a significant performance penalty when they are loaded into a process. The performance penalty can be in the form of memory usage, CPU usage, elapsed time, or even address space consumption. The CLR, JavaScript/ECMAScript, and Java are known to be high-impact runtimes. Since in-process extensions can be loaded into many processes, and are often done so at performance-sensitive moments (such as when preparing a menu to be displayed the user), high-impact runtimes can negatively impact overall responsiveness.

A high-impact runtime that consumes significant resources can cause a failure in the host process or another in-process extension. For example, a high-impact runtime that consumes hundreds of megabytes of address space for its heap can result in the host application being unable to load a large dataset. Furthermore, because in-process extensions can be loaded into multiple processes, high resource consumption in a single extension can quickly multiply into high resource consumption across the entire system.

If a runtime remains loaded or otherwise continues to consume resources even when the extension that uses that runtime has unloaded, then that runtime is not suitable for use in an extension.

Issues Specific to the .NET Framework

The following sections discuss examples of issues found with using managed code for extensions. They are not a complete list of all possible issues that you might encounter. The issues discussed here are both reasons that managed code is not supported in extensions and points to consider when you evaluate the use of other runtimes.

  • Re-entrancy
    When the CLR blocks a single-threaded apartment (STA) thread, for example, due to a Monitor.Enter, WaitHandle.WaitOne, or contended lock statement, the CLR, in its standard configuration, enters a nested message loop while it waits. Many extension methods are prohibited from processing messages, and this unpredictable and unexpected reentrancy can result in anomalous behavior which is difficult to reproduce and diagnose.

  • The Multithreaded Apartment The CLR creates Runtime Callable Wrappers for Component Object Model (COM) objects. These same Runtime Callable Wrappers are destroyed later by the CLR's finalizer, which is part of the multithreaded apartment (MTA). Moving the proxy from the STA to the MTA requires marshaling, but not all interfaces used by extensions can be marshalled.

  • Non-Deterministic Object Lifetimes
    The CLR has weaker object lifetime guarantees than native code. Many extensions have reference count requirements on objects and interfaces, and the garbage-collection model employed by the CLR cannot fulfill these requirements.

    • If a CLR object obtains a reference to a COM object, the COM object reference held by the Runtime Callable Wrapper is not released until the Runtime Callable Wrapper is garbage-collected. Nondeterministic release behavior can conflict with some interface contracts. For example, the IPersistPropertyBag::Load method requires that no reference to the property bag be retained by the object when the Load method returns.
    • If a CLR object reference is returned to native code, the Runtime Callable Wrapper relinquishes its reference to the CLR object when the Runtime Callable Wrapper's final call to Release is made, but the underlying CLR object is not finalized until it is garbage-collected. Nondeterministic finalization can conflict with some interface contracts. For example, thumbnail handlers are required to release all resources immediately when their reference count drops to zero.

Acceptable Uses of Managed Code and Other Runtimes

It is acceptable to use managed code and other runtimes to implement out-of-process extensions. Examples of out-of-process Shell extensions include the following:

  • Preview handlers
  • Command-line-based actions such as those registered under shell\verb\command subkeys.
  • COM objects implemented in a local server, for Shell extension points that allow out-of-process activation.

Some extensions can be implemented either as in-process or out-of-process extensions. You can implement these extensions as out-of-process extensions if they do not meet these requirements for in-process extensions. The following list shows examples of extensions that can be implemented as either in-process or out-of-process extensions:

  • IExecuteCommand associated with a DelegateExecute entry registered under a shell\verb\command subkey.
  • IDropTarget associated with the CLSID registered under a shell\verb\DropTarget subkey.
  • IExplorerCommandState associated with a CommandStateHandler entry registered under a shell\verb subkey.

SharpShell

SharpShell makes it easy to create Windows Shell Extensions using the .NET Framework.

The source code is hosted on https://github.com/dwmkerr/sharpshell - you can post questions and feature request here or there. Supported Extensions

You can use SharpShell to build any of the extensions below:

  • Shell Context Menus
  • Icon Handlers
  • Info Tip Handlers
  • Drop Handlers
  • Preview Handlers
  • Icon Overlay Handlers
  • Thumbnail Hanlders
  • Property Sheet Extensions

Projects that use SharpShell
1. Trello Context Menu
2. REAL Shuffle Player 2.0

Article Series at CodeProject

  • .NET Shell Extensions - Shell Context Menus
  • .NET Shell Extensions - Shell Icon Handlers
  • .NET Shell Extensions - Shell Info Tip Handlers
  • .NET Shell Extensions - Shell Drop Handlers
  • .NET Shell Extensions - Shell Preview Handlers
  • .NET Shell Extensions - Shell Icon Overlay Handlers
  • .NET Shell Extensions - Shell Thumbnail Handlers
  • .NET Shell Extensions - Shell Property Sheets
like image 30
Ehsan Mohammadi Avatar answered Oct 05 '22 21:10

Ehsan Mohammadi