Multiple Servers under one common ContextMenuStrip

Nov 24, 2014 at 6:42 AM
Edited Nov 24, 2014 at 6:45 AM
Hi,

I just started to use SharpShell in order to install several ContextMenuServers associated with various file extension classes. I'm currently a little bit stucked in how to have these multiple servers arranged as DropDownItems under one common ContextMenuStrip.
I.e.:
-> MyContextMenuItem
  -> Server 1
  -> Server 2
As far as I see, the Constructor of all the servers is called each time that I right click on a file. The order of calls is as follows:
Server 1 Constructor
Server 1 CanShowMenu
Server 1 CreateMenu

Server 2 Constructor
Server 2 CanShowMenu
Server 2 CreateMenu
etc.

At first I tried with a static class providing the ContextMenuStrip. But this will not work when clicking on different kind of files which is supported by different servers. The sub items from the servers that where registered with the file that was clicked before are not removed. Removing them in the constructors of the Servers doesn't help as the first Server already has the menu before the constructor of the second is called which would remove it.

For me the only way to accomplish this seems to be to have one parent extensions that is registered with all file classes of all "real" servers and then iterates over all its "child" servers in each call of CanShowMenu and CreateMenu to build up the menu.

Is my assumption correct or is ther any better way to accomplish such a scenario? Actually It would be good to have a reference to the ContextMenu that will be shown and search for the common ContextMenuStrip, then create it if its not yet there, and add the appropriate Sub item to that reference...

I hope you understand what I'm talking about. If its unclear, please let me know.

Regards

Tobias

Edit:

An alternative would be to change the order of calls of the Server classes to the following:
Server 1 Constructor
Server 2 Constructor
Server 1 CanShowMenu
Server 2 CanShowMenu
Server 1 CreateMenu
Server 2 CreateMenu
Coordinator
Nov 30, 2014 at 4:24 PM
Hi Tobias,

Thanks for getting in touch! So with the servers and the files, is it multiple servers always for the same types of files? Such as:

.123, .456, *.789: Server1, Server2

Or is it more of a mix and match?

.123, .456: Server1
.123, .789: Server2
.456, .789: Server3, Server 4

And so on? If it's the first case, having one more complex server which offers the functionality might be easier than having multiple servers.

One thing that will be hard will be to have a single 'dynamic' server, one which builds a context menu for a specific file (rather than for a specific file type), which is a shame because it sounds like this might be more what you need. If so, would a single server which can inspect the type of file and maybe the file contents and then build a dynamic menu be more what you are after? Because there is support for this (with a bit of work).

Cheers,

Dave
Dec 1, 2014 at 10:31 AM
Hi Dave,

It's more like the second case you described. At first, in order to seperate concerns, I planned having one server for each functionality I want to provide (so not actually having as many server as supported file classes but as many as functions provided) e.g.

(The examples are made up from complete nonsense but they show the point)
Lets assume I would have one functionality that counts the number of words in a txt file and one that counts the lines this would lead to having the two servers:
ServerCountWordsInTXT
ServerCountLinesInTXT
Now lets assume I have another functionality to check for the resolution of bitmaps this would for example lead to
ServerDetermineResolutionOnPNG
And maybe I have another functionality to query the Author of txt files and bitmaps (As I said: The examples are all bullshit)
ServerToGetAuthorInTXTAndPNG
So finally I'm having four servers which all don't know each other and I want all of them to put their menu as a DropDownItem under a common menu entry. But as the servers don't know the ContextMenu itself and also don't know If they are the first and/or only server that can show a menu for a certain file, it is impossible to tell where and when to create the common menu entry under which they should add their stuff.

So the only solution on an integration level that I see is:
  • Implement exactly one Server
  • Implement n "ContextMenuExtender" classes
    ---- and now the ugly part ---
  • for every "ContextMenuExtender", the developer of this has to know that he has to create an instance of this type in the constructor of the Server which then adds it to an internal list to query all instances in this list in the CanShowMenu and CreateMenu methods to aggregate them.
  • secondly if the server is not yet registered for the class of file extensions the new "ContextMenuExtender" is capable of handling, the developer has to know that he has to add an appropriate Argument to the Servers class definition.
So this solution requires a lot of shared knowledge and developers that pay special attention to what they do (which in my experience will lead to trouble at some point in time) Of course one could also think of putting another layer of indirection here and using some Plugin mechanisms with MEF loading and not what but this will make the constructor of the Server quite heavy and "long" running which is not acceptable when we want to show the context menu with acutally no delay...
Coordinator
Dec 14, 2014 at 8:55 AM
I see the problem. It's quite a complex one because it involves either making some kind of dynamic context menu (which is not supported out of the box by SharpShell, but with some work can be handled), or changing SharpShell to allow each extension to search the context menu for a given parent item, create it if it does not exist and then add it's own context menu item as a child. I'll see if I can find some code that shows an example of this, but it looks like you may end up having to customise SharpShell...