sharpshell
sharpshell copied to clipboard
CreateMenu called twice and wrong submenu invoked
Version of SharpShell used: 2.3.2
Related type(s) of SharpShell-Server: [COMServerAssociation(AssociationType.AllFiles)]
I am using the shell context menu feature. I build a tree of ToolStripItemMenu objects and hang them off the context menu. Everything is visually formed correctly on the screen, however I can see that there are various problems occurring that eventually result in the wrong submenu item getting selected.
The first problem that I can see in my code is that it appears that SharpShell is calling into my code and calling CreateMenu twice. The first call to CreateMenu comes when I right mouse click after highlighting 20 files in a folder. This makes sense and is expected because I registered my code using [COMServerAssociation(AssociationType.AllFiles)]. After this first call into CreateMenu the context menu appears and I see my top-level entry. I am able to mouseover and walk down a list of submenu items hanging off this top-level entry. When I get down to the submenu item that I want to click I select with the left mouse button. At this point SharpShell appears to create a whole new instance of my menu class and call CreateMenu on it. I did not expect a second call - which causes issues because I end up building a whole new tree of menu items.
In my debugging I noticed something else peculiar. Even though I have selected 20 files and right clicked, the SharpShellLog.txt file I created with sharp shell logging lists only 16 items. However, upon the second instantiation of my code and the secondary call to CreateMenu sharp shell logging lists 20 items.
I see the same thing in my code - 16 selected items passed the first time in and 20 items passed the second time in.
Finally, in the sharp shell log I can see "Invoke command index 10". I went and looked at the menu tree that I had built. My menu tree has something on the order of 300 items in it. I had clicked on item 192, yet when my menu event handler was triggered, it was item 10 that caught the event. So it appears as though sharp shell is not properly detecting which submenu item was actually clicked.
Log Messages -- Here are two logs. First is the log when I select 20 items and the defective behavior occurs. Down below this I am including another log where I select only 16 items and the defective behavior does not occur. In this first example, you can see the command index shows up as 10. In the other log down below you can see that it shows up as 192.
Message: SharpShell Diagnostics Initialised. Process explorer.
Message: MenuExtension: Initializing shell extension...
Message: MenuExtension: Shell extension initialised.
Parent folder:
Log Messages -- Here I select only 16 items. My code only gets called a single time and the submenu clicked is the proper one at index 192.
Message: SharpShell Diagnostics Initialised. Process explorer.
Message: MenuExtension: Initializing shell extension...
Message: MenuExtension: Shell extension initialised.
Parent folder:
Do you have a chance to update the used SharpShell Package to the latest version 2.7.2 ?
I have tested with 2.7.2 just now and the problem behavior still exists. I got basically the same log as shown above with some time stamp decorations that appear to be a new feature in 2.7.2 or some intervening release.
So my issue stands. Any help is very much appreciated.
This seems to be related to the issue #4. Some troubleshooting advise can be found in the docs
Definitely related to issue #4, but also a little bit of a different issue. I posted a message into issue #4 where I described that I have seen the issue where my code is called with 16 items then called a second time with the full list of 20 selected files. Got it, and no problem for me on that point.
The fatal issue for me is that my onclick handlers for the various submenu items that I create are not getting called correctly. Sharp shell is invoking menu item number 10 in my list of submenus when the user actually clicked on submenu item number 192. This is a different issue though very related to the issue addressed in issue #4.
Let us work on your issue here, as the other one is closed already.
I suggest, to eliminate the Operating System behavior as a potential source of your issue by setting the mentioned registry on your machine to a high value (eg. 100), restart explorer.exe or logoff and logon again and test afterwards.
I appreciate and commend your conscientious response. I will set the registry entry and test again then report back on whether it makes the issue disappear. I think I tried this before and it didn't make a difference, but I will test again and report the results.
I have set MultipleInvokePromptMinimum registry key to 100 files. It did not change the behavior wherein the submenu invoke sends the event to the 10th submenu rather than the 192nd submenu, where the 192nd submenu item is the one that I clicked on.
I suppose that recreating this could be rather straight forward. If you create a right mouse menu item that has 2 children, each of those has 10 children and each of those children has 10 children - this will give you a tree of 200 ToolStripMenuItem controls. Assign a onclick handler that tells you which item you clicked. Then select 20 files, right mouse, select one of the menu items close to the 200th item and see what it tells you that you clicked. In my app it would tell me 'you clicked the 10th menu item'.
I wrote a test case for this. Below is some code for CreateMenu. I ended up having to build out 500 submenus before I could trip the problem. In the code below the menus are named uniquely and they each have a simple click handler. Around menu 495 is where things go wrong. In my zero-numbered scheme this is grandchild menu 3_8_5. If you click a grandchild before that one then happy result - message box pops up. If you click one after that then no message box appears.
protected override ContextMenuStrip CreateMenu()
{
ToolStripMenuItem MainMenu;
MainMenu = new ToolStripMenuItem
{
Text = "TEST MENU",
};
MainMenu.Font = new Font(MainMenu.Font, FontStyle.Italic | FontStyle.Bold);
for (int i = 0; i < 5; i++)
{
string menuText = "Parent_" + i;
ToolStripMenuItem parentMenu = new ToolStripMenuItem { Text = menuText };
for (int j = 0; j < 10; j++)
{
menuText = "Child_" + i + "_" + j;
ToolStripMenuItem childMenu = new ToolStripMenuItem { Text = menuText };
for (int k = 0; k < 10; k++)
{
menuText = "Grandchild_" + i + "_" + j + "_" + k;
ToolStripMenuItem grandChildMenu = new ToolStripMenuItem { Text = menuText };
//avoid variable capture by using local
var msgText = menuText;
grandChildMenu.Click += (sender, args) =>
{
MessageBox.Show("You have clicked grandchild menu: " + msgText);
};
childMenu.DropDownItems.Add(grandChildMenu);
}
parentMenu.DropDownItems.Add(childMenu);
}
MainMenu.DropDownItems.Add(parentMenu);
}
menu.Items.Add(MainMenu);
return menu;
}
Actually, here is a slightly better test case. In this menu I changed the code slightly so that the grandchild menus all show with the same name. When you click, you are given coordinates on what menu item was selected despite their identical names at the grandchild level.
What I see in this code is that it works correctly when I have selected fewer than 17 files. However, if I select more than 16 files the click event goes to the wrong menu item -> Grandchild_0_0_0 even though I clicked on Grandchild_2_5_2
protected override ContextMenuStrip CreateMenu()
{
ToolStripMenuItem MainMenu;
MainMenu = new ToolStripMenuItem
{
Text = "TEST MENU",
};
MainMenu.Font = new Font(MainMenu.Font, FontStyle.Italic | FontStyle.Bold);
for (int i = 0; i < 5; i++)
{
string menuText = "Parent_" + i;
ToolStripMenuItem parentMenu = new ToolStripMenuItem { Text = menuText };
for (int j = 0; j < 10; j++)
{
menuText = "Child_" + i + "_" + j;
ToolStripMenuItem childMenu = new ToolStripMenuItem { Text = menuText };
for (int k = 0; k < 10; k++)
{
//make every grandchild menu show up with the same name
//this seems to trip up the code and cause selection of the wrong menu
menuText = "Grandchild";
ToolStripMenuItem grandChildMenu = new ToolStripMenuItem { Text = menuText };
//avoid variable capture by using local
var msgText = "Grandchild_" + i + "_" + j + "_" + k;
grandChildMenu.Click += (sender, args) =>
{
MessageBox.Show("You have clicked grandchild menu: " + msgText);
};
childMenu.DropDownItems.Add(grandChildMenu);
}
parentMenu.DropDownItems.Add(childMenu);
}
MainMenu.DropDownItems.Add(parentMenu);
}
menu.Items.Add(MainMenu);
return menu;
}
Thank you for the test code. I can have a look at it earliest this evening.
With your test code, I was able to reproduce your issue on my machine too.
A quick internet search also shows, that the invocation logic of windows seems to be key in your scenario.
- Windows Shell extention: context menu when more than 16 files are selected - Stack Overflow
- Shell Extension Context Menu in C# strange error
For now, it looks like an issue, that needs to be adressed in the lower code levels.
Should I assume that the SharpShell project will not be fixing this issue? In other words, should I assume that if anyone addresses the "lower code levels" it will not be a SharpShell code change, but rather a Windows OS code change?
The double invocation of the extension is triggered by Windows, when more than 16 files are selected, which is by design of Microsoft.
I digged deeper into the problem, and it turns out, that Windows seems to send back the identifier for the FIRST menu item having the TEXT of the item the user has selected.
When I made the text property of the grandchild nodes unique, the right message got shown.
@DarkCreekWay Thank you very much for the dialog around this issue as it has increased my team's understanding of the lower level issues. Can you render a decision as to whether this is something that you (a) have the power to address in your code layer and (b) have the intent to address in some time frame? I don't want to infer incorrectly that this is either on or off roadmap/backlog.
@jleveille1337: The double invocation is triggered by Windows itself, so it is by OS design, and nothing, that can be fixed by the SharpShell project.
To overcome the problem of the wrong item click event is triggered, you have to ensure, that each of the menu items you create hase a unique text set. The context menu should behave correctly afterwards.
As I'm not the owner of the project, I cannot say anything about a timeline or plans for fixes or improvements.
Thank you @DarkCreekWay you have been very helpful and it is appreciated.