none
Create custom menu item in Right click context menu RRS feed

  • Question

  • Hello All,

    We have a C# win form application which creates certain folders on the file system. We have to show a custom menu item when user right clicks inside these folders. I know that we can achieve it using creating a COM component and implementing IShellExtInit and IContextMenu event handlers in C++. I have couple of queries:

    1. Is there a way to do it in C# itself so that we need not write code in C++ and C# code can be reused?

    2. If not, is there a way to open C# win form from the context menu custom item so that existing c# code can be reused rather than developing win form in c++

    Looking for guidance on best practices from architecture/design perspective.

    Thanks.

    Tuesday, May 21, 2019 2:58 PM

All replies

  • Hi 

    Thank you for posting here.

    For your question, you want to create custom menu item in right click conntext menu.

    Based on my research, there is no direct way to do it in c#. If you want to open c# winform from the context menu custom item, you could try to use Process.Start method in the Right-click event handler.

    Also, I find the following link may be helpful for you.

    https://www.codeproject.com/Articles/174369/How-to-Write-Windows-Shell-Extension-with-NET-Lang​​​​​​​

    Best Regards,

    Jack


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Wednesday, May 22, 2019 2:18 AM
    Moderator
  • 1. You can write managed shell extensions. It is supported since .NET 4.

    2. Context menus do not require custom code to be written if you just want to show some option. That can be done via a registry entry. The only time you need to actually write a context menu provider is if you need to be able to dynamically adjust the context menu based upon some calculations you are doing against the file. As an example a comparison tool I use generates 2 different context menus depending upon whether I've already selected a file/folder for selection. That requires a context menu provider. However I have a registry entry configured such that when I right-click a NuGet package I can automatically push it to NuGet. Since this functionality shows up for all NuGet package files it is simply a registry entry.


    Michael Taylor http://www.michaeltaylorp3.net

    Thursday, May 23, 2019 2:49 PM
    Moderator
  • For folders, you can add a key in HKEY_CLASSES_ROOT\Directory\shell

    (+ the subkey command to launch your application)

    Thursday, May 23, 2019 4:05 PM
  • Thank you for your response. I see that writing managed shell extension is supported starting .net 4 as it will allow you to load multiple CLR in process but msdn document "Guidance for Implementing In-Process Extensions" recommends against it.

    "Microsoft recommends against writing managed in-process extensions to Windows Explorer or Windows Internet Explorer and does not consider them a supported scenario."

    This makes me think if it is okay to go ahead with shell extension in C# or not?

    Also - our custom context menu option would be displayed based on some logic so we do need to do it programmatically only.

    So if writing shell extension in C# is not supported, is there any way to open the win form developed in C# from the context menu item developed using c++ code. I read that there is a way to do this making the c# form as active x control but not really sure if making active x control is also recommended.

    Friday, May 24, 2019 9:42 AM
  • While MS doesn't formally support managed extensions you'll find they are used in the wild anyway. MS originally had this recommendation because it wouldn't work prior to v4. With v4 it now works but there are some challenges with working with COM (in any type of app) and therefore MS updated the docs to provide some areas to be aware of. However writing a context menu in C# should be fine as it isn't a heavy duty component. There are managed shell extensions that do a lot more than just context menus and they work fine, once tested. It is up to you but here's a link to some starter code (note that most of these are old and therefore would need to be updated).

    https://www.codeproject.com/Articles/512956/NET-Shell-Extensions-Shell-Context-Menus
    https://github.com/dwmkerr/sharpshell

    https://social.msdn.microsoft.com/Forums/vstudio/en-US/7ceb44d5-dce8-4197-ac55-f0f4fb59eeb4/how-can-i-write-managed-shell-extension-in-net-4?forum=clr

    The hard part is getting all the COM-based Shell stuff set up. MS released in the early days of .NET A Windows API Code Pack that included shell extension stuff. They have since let this project die but somebody posted the source in GitHub and created NuGet packages. Part of the code contains the COM stuff needed for a portion of the shell extension logic.

    As for C++ and C#. Outside of ActiveX you cannot call a component in C# from C++. However that isn't how you'd do it anyway. A shell extension should be a simple, standalone DLL. It should determine what needs to be displayed and then invoke the correct action. That action should be to call your external process. A process can call any other process written in a different language. So the "correct" solution to me is either write a simple C# shell extension (or use C++ if you have the experience) to implement the context menu logic and invoke the actual process. The actual process is your program written in C# that runs by you calling Process.Start. 

    The reason why this is important is that you probably want to be able to run your app outside the shell context menu. Therefore it needs to be a program anyway. Furthermore you want your app to run in the context of the user, not the shell so you wouldn't want to invoke it within the shell process.


    Michael Taylor http://www.michaeltaylorp3.net

    Friday, May 24, 2019 2:07 PM
    Moderator
  • Also - our custom context menu option would be displayed based on some logic so we do need to do it programmatically only.

    It can also be done with registry : you can remove the menu item on EVENT_SYSTEM_MENUPOPUPSTART

    (+ "AppliesTo" to display the menu item for a particular directory)

    (tested on Windows 10)


    Friday, May 24, 2019 3:24 PM
  • While MS doesn't formally support managed extensions you'll find they are used in the wild anyway. MS originally had this recommendation because it wouldn't work prior to v4. With v4 it now works but there are some challenges with working with COM (in any type of app) and therefore MS updated the docs to provide some areas to be aware of. However writing a context menu in C# should be fine as it isn't a heavy duty component. There are managed shell extensions that do a lot more than just context menus and they work fine, once tested. It is up to you but here's a link to some starter code (note that most of these are old and therefore would need to be updated).

    The hard part is getting all the COM-based Shell stuff set up. MS released in the early days of .NET A Windows API Code Pack that included shell extension stuff. They have since let this project die but somebody posted the source in Github and created NuGet packages. Part of the code contains the COM stuff needed for a portion of the shell extension logic.

    As for C++ and C#. Outside of ActiveX you cannot call a component in C# from C++. However that isn't how you'd do it anyway. A shell extension should be a simple, standalone DLL. It should determine what needs to be displayed and then invoke the correct action. That action should be to call your external process. A process can call any other process written in a different language. So the "correct" solution to me is either write a simple C# shell extension (or use C++ if you have the experience) to implement the context menu logic and invoke the actual process. The actual process is your program written in C# that runs by you calling Process.Start. 

    The reason why this is important is that you probably want to be able to run your app outside the shell context menu. Therefore it needs to be a program anyway. Furthermore you want your app to run in the context of the user, not the shell so you wouldn't want to invoke it within the shell process.


    Thank you very much for detailed response. This is very helpful.

    I am worried as that article was updated an year ago and while .net 4 is out for quite a long time now. So not sure if we'll be carrying any risk here and may get into issues at later point of time. MS doesn't mention that they don't support it only for .net lower than .net4.

    You are correct that shell extension is a standalone DLL. So I will try out calling the actual program from shell extension via Process.Start as you suggested.

    I will try out the C# option to create context menu. It will just make it very simple to have everything in C#. Would we be able to invoke C# win form from context menu created using C# without making win form as ActiveX?  Just wanted to check. I will try out Program.Start method anyway.

    Monday, May 27, 2019 8:16 AM
  • If the winforms is an app that you invoke via Process.Start then you don't need ActiveX. If you want to host a Winforms UI (via ActiveX) inproc with your context handler (which is in inproc of the shell) then it can be done but it isn't pretty unless you already know COM. Specifically you have to get your native DLL to have a message pump (which we generally used MFC for in the past) but that has mostly fallen to the wayside. You then have to integrate your ActiveX message handling with the main message pump of your handler. How to do this is documented here. There are other articles as well. 

    Also note that you can do COM+ which would start moving toward out of process managed calls but at that point a simple Process.Start would be easier.


    Michael Taylor http://www.michaeltaylorp3.net

    Monday, May 27, 2019 3:40 PM
    Moderator
  • If the winforms is an app that you invoke via Process.Start then you don't need ActiveX. If you want to host a Winforms UI (via ActiveX) inproc with your context handler (which is in inproc of the shell) then it can be done but it isn't pretty unless you already know COM. Specifically you have to get your native DLL to have a message pump (which we generally used MFC for in the past) but that has mostly fallen to the wayside. You then have to integrate your ActiveX message handling with the main message pump of your handler. How to do this is documented here. There are other articles as well. 

    Also note that you can do COM+ which would start moving toward out of process managed calls but at that point a simple Process.Start would be easier.


    It is a winform application and deployable is exe. I will try to launch the exe using Process.Start and then apply the logic in the main method to open the required winform in UI based on the argument passed. I hope it works well with UI forms.

    We do not have c++ skill and also it will be easier to maintain the code in one language. We have to duplicate some of the code today as it is required in both c# app as well as in c++ extension.


    Monday, May 27, 2019 4:30 PM
  • If the winforms is an app that you invoke via Process.Start then you don't need ActiveX. If you want to host a Winforms UI (via ActiveX) inproc with your context handler (which is in inproc of the shell) then it can be done but it isn't pretty unless you already know COM. Specifically you have to get your native DLL to have a message pump (which we generally used MFC for in the past) but that has mostly fallen to the wayside. You then have to integrate your ActiveX message handling with the main message pump of your handler. How to do this is documented here. There are other articles as well. 

    Also note that you can do COM+ which would start moving toward out of process managed calls but at that point a simple Process.Start would be easier.


    It is a winform application and deployable is exe. I will try to launch the exe using Process.Start and then apply the logic in the main method to open the required winform based on the argument passed.

    We do not have c++ skill and also it will be easier to maintain the code in one language. We have to duplicate some of the code today as it is required in both c# app as well as in c++ extension.

    One more assistance I needed - which logging framework we can use that work on C++ COM component likeright click context menu.I did implement my custom log class in C++ but it just doesn't log to file system from within context menu code. It worksfine in a project which is not COM.
    Monday, May 27, 2019 6:04 PM
  • For questions related to C++ please post in the C++ forums. They can point you to good logging frameworks that might be available and that meet your specific needs.

    Michael Taylor http://www.michaeltaylorp3.net

    Tuesday, May 28, 2019 12:14 AM
    Moderator