Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. C#
  4. IContextMenu Shell Extension - HandleMenuMsg

IContextMenu Shell Extension - HandleMenuMsg

Scheduled Pinned Locked Moved C#
linuxdebuggingquestion
10 Posts 2 Posters 0 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • L Offline
    L Offline
    LoKi_za
    wrote on last edited by
    #1

    I'm putting together a project and need to extend Windows' shell to add a owner-drawn menu item to the context menu. If I use only IContextMenu, the menu item and owner-drawn (blank) sub menu are added fine. As soon as I implement IContextMenu2 and HandleMenuMsg, I get a memfault from Explorer whilst debugging. A breakpoint is hit inside the IContextMenu2.HandleMenuMsg but subsequently, Explorer crashes. I'm returning "0" from int HandleMenuMsg(uint, IntPtr, IntPtr). Any ideas? -------------------------------- Extension code: [ComImport(), InterfaceType(ComInterfaceType.InterfaceIsIUnknown), GuidAttribute("000214e8-0000-0000-c000-000000000046")] public interface IShellExtInit { [PreserveSig()] int Initialize (IntPtr pidlFolder, IntPtr lpdobj, uint /*HKEY*/ hKeyProgID); } [ComImport(), InterfaceType(ComInterfaceType.InterfaceIsIUnknown), GuidAttribute("000214e4-0000-0000-c000-000000000046")] public interface IContextMenu { [PreserveSig()] int QueryContextMenu(HMenu hmenu, int iMenu, int idCmdFirst, int idCmdLast, CMF uFlags); [PreserveSig()] void InvokeCommand(IntPtr pici); [PreserveSig()] void GetCommandString(int idcmd, uint uflags, int reserved, StringBuilder commandstring, int cch); } [ComImport(), InterfaceType(ComInterfaceType.InterfaceIsIUnknown), GuidAttribute("000214e4-0000-0000-c000-000000000046")] public interface IContextMenu2 : IContextMenu { [PreserveSig()] int HandleMenuMsg(uint Msg, IntPtr LParam, IntPtr WParam); [PreserveSig()] new int QueryContextMenu(HMenu hmenu, int iMenu, int idCmdFirst, int idCmdLast, CMF uFlags); [PreserveSig()] new void InvokeCommand(IntPtr pici); [PreserveSig()] new void GetCommandString(int idcmd, uint uflags, int reserved, StringBuilder commandstring, int cch); } -------------------------------- Shell code: public int QueryContextMenu(HMenu hmenu, int iMenu, int idCmdFirst, int idCmdLast, CMF uFlags) { // HMenu AppMenu; Int32 NewMenuID = 1; // Check Flags if ((uFlags & (CMF.CMF_VERBSONLY|CMF.CMF_DEFAULTONLY|CMF.CMF_NOVERBS)) == 0 || (uFlags & CMF.CMF_EXPLORE) != 0) { // // Create Popup Menu AppMenu = Helpers.CreatePopupMenu(); // Append SubMenus Helpers.AppendMenu(AppMenu, MFMENU.MF_OWNERDRAW|MFMENU.MF_ENABLED, new IntPtr(idCmdFirst + NewMenuID++), null); Helpers.InsertMenu(hmenu, 3, MFMENU.MF_BYPOSITION|MFMENU.MF_POPUP|MFMENU.MF_ENABLED, AppMenu.handle, "MediaExplorer"); } return NewMenuID; } #region IConte

    W 1 Reply Last reply
    0
    • L LoKi_za

      I'm putting together a project and need to extend Windows' shell to add a owner-drawn menu item to the context menu. If I use only IContextMenu, the menu item and owner-drawn (blank) sub menu are added fine. As soon as I implement IContextMenu2 and HandleMenuMsg, I get a memfault from Explorer whilst debugging. A breakpoint is hit inside the IContextMenu2.HandleMenuMsg but subsequently, Explorer crashes. I'm returning "0" from int HandleMenuMsg(uint, IntPtr, IntPtr). Any ideas? -------------------------------- Extension code: [ComImport(), InterfaceType(ComInterfaceType.InterfaceIsIUnknown), GuidAttribute("000214e8-0000-0000-c000-000000000046")] public interface IShellExtInit { [PreserveSig()] int Initialize (IntPtr pidlFolder, IntPtr lpdobj, uint /*HKEY*/ hKeyProgID); } [ComImport(), InterfaceType(ComInterfaceType.InterfaceIsIUnknown), GuidAttribute("000214e4-0000-0000-c000-000000000046")] public interface IContextMenu { [PreserveSig()] int QueryContextMenu(HMenu hmenu, int iMenu, int idCmdFirst, int idCmdLast, CMF uFlags); [PreserveSig()] void InvokeCommand(IntPtr pici); [PreserveSig()] void GetCommandString(int idcmd, uint uflags, int reserved, StringBuilder commandstring, int cch); } [ComImport(), InterfaceType(ComInterfaceType.InterfaceIsIUnknown), GuidAttribute("000214e4-0000-0000-c000-000000000046")] public interface IContextMenu2 : IContextMenu { [PreserveSig()] int HandleMenuMsg(uint Msg, IntPtr LParam, IntPtr WParam); [PreserveSig()] new int QueryContextMenu(HMenu hmenu, int iMenu, int idCmdFirst, int idCmdLast, CMF uFlags); [PreserveSig()] new void InvokeCommand(IntPtr pici); [PreserveSig()] new void GetCommandString(int idcmd, uint uflags, int reserved, StringBuilder commandstring, int cch); } -------------------------------- Shell code: public int QueryContextMenu(HMenu hmenu, int iMenu, int idCmdFirst, int idCmdLast, CMF uFlags) { // HMenu AppMenu; Int32 NewMenuID = 1; // Check Flags if ((uFlags & (CMF.CMF_VERBSONLY|CMF.CMF_DEFAULTONLY|CMF.CMF_NOVERBS)) == 0 || (uFlags & CMF.CMF_EXPLORE) != 0) { // // Create Popup Menu AppMenu = Helpers.CreatePopupMenu(); // Append SubMenus Helpers.AppendMenu(AppMenu, MFMENU.MF_OWNERDRAW|MFMENU.MF_ENABLED, new IntPtr(idCmdFirst + NewMenuID++), null); Helpers.InsertMenu(hmenu, 3, MFMENU.MF_BYPOSITION|MFMENU.MF_POPUP|MFMENU.MF_ENABLED, AppMenu.handle, "MediaExplorer"); } return NewMenuID; } #region IConte

      W Offline
      W Offline
      Wraith2
      wrote on last edited by
      #2

      I don't think you need the redefinitions of IContextMenu methods in there, they may be causing your the problem when it tries to marshal the interface. Even if your interface inherits another interface, in this case IContextMenu2 : IContextMenu, you don't redefine the members from the original interface. Also, if i remember correctly, there is an entry on Raymod Kim's blog as well an anecdotal evidence that IContextMenu2 isn't very useful. The system checks for IContextMenu2 and if present then tries to use IContextMenu3, if that isn't present it falls back to the original IContextMenu. So you will need to implement the 3 interface for it to work i think. I think your definitions of IContextMeuu are wrong as well. PreserveSig is used to prevent the signiture being changed because typically COM methods will return an HResult value. Your methods aren't returning HResult (or int) values and yet you've marked them with PreserveSig. Either remove the attribute or change the function definitions to match the definitions found in the header files exactly, otherwise i think you're either hiding errors or causing deeper problems which may not be apparent until the shell dies on you.

      L 1 Reply Last reply
      0
      • W Wraith2

        I don't think you need the redefinitions of IContextMenu methods in there, they may be causing your the problem when it tries to marshal the interface. Even if your interface inherits another interface, in this case IContextMenu2 : IContextMenu, you don't redefine the members from the original interface. Also, if i remember correctly, there is an entry on Raymod Kim's blog as well an anecdotal evidence that IContextMenu2 isn't very useful. The system checks for IContextMenu2 and if present then tries to use IContextMenu3, if that isn't present it falls back to the original IContextMenu. So you will need to implement the 3 interface for it to work i think. I think your definitions of IContextMeuu are wrong as well. PreserveSig is used to prevent the signiture being changed because typically COM methods will return an HResult value. Your methods aren't returning HResult (or int) values and yet you've marked them with PreserveSig. Either remove the attribute or change the function definitions to match the definitions found in the header files exactly, otherwise i think you're either hiding errors or causing deeper problems which may not be apparent until the shell dies on you.

        L Offline
        L Offline
        LoKi_za
        wrote on last edited by
        #3

        Thanks for the comments Wraith. In the .NET SDK, the IContext Interface is specified as such: // IContextMenu methods [PreserveSig()] int QueryContextMenu(uint hmenu, uint iMenu, int idCmdFirst, int idCmdLast, uint uFlags); [PreserveSig()] void InvokeCommand (IntPtr pici); [PreserveSig()] void GetCommandString(int idcmd, uint uflags, int reserved, StringBuilder commandstring, int cch); That's where I got it from. I've repeated the interface methods in the implemented IContextMenu2 because I read several articles that stated the implemented interfaces in COM interop fail if you don't redefine the methods. Wierd I know. I did have IContextMenu3 implemented as well but was receiving the same problem so I took it out to try and find which was causing the error. All implemented interface methods in my class receive notification (IShellExtInit.Initialize(), IContextMenu.QueryContextMenu() etc.) but the shell/explorer fails after having sent notification to IContextMenu2.HandleMenuMsg a few times. :confused: I'll try implement IContextMenu3 as well. Also, what should be returned from IContextMenu2.HandleMenuMsg()? 0? One of the params? >:)

        W 1 Reply Last reply
        0
        • L LoKi_za

          Thanks for the comments Wraith. In the .NET SDK, the IContext Interface is specified as such: // IContextMenu methods [PreserveSig()] int QueryContextMenu(uint hmenu, uint iMenu, int idCmdFirst, int idCmdLast, uint uFlags); [PreserveSig()] void InvokeCommand (IntPtr pici); [PreserveSig()] void GetCommandString(int idcmd, uint uflags, int reserved, StringBuilder commandstring, int cch); That's where I got it from. I've repeated the interface methods in the implemented IContextMenu2 because I read several articles that stated the implemented interfaces in COM interop fail if you don't redefine the methods. Wierd I know. I did have IContextMenu3 implemented as well but was receiving the same problem so I took it out to try and find which was causing the error. All implemented interface methods in my class receive notification (IShellExtInit.Initialize(), IContextMenu.QueryContextMenu() etc.) but the shell/explorer fails after having sent notification to IContextMenu2.HandleMenuMsg a few times. :confused: I'll try implement IContextMenu3 as well. Also, what should be returned from IContextMenu2.HandleMenuMsg()? 0? One of the params? >:)

          W Offline
          W Offline
          Wraith2
          wrote on last edited by
          #4

          Can you privode a link, or tell me how to find that definition you used? Because it seems to be contrary to the documentation i've read. I also couln'dt find a useful implementation of IContextMenu and provided my own. While i cant claim its perfect i've not had any problems with the shell crashing in quite a while now so i think i'm at or close to a correct definition. I'd also be interested to see those articles, i've read around COM interop articles a bit lately and i've not found any that specifically mentioned the redefinition argument. IContextMenu2.HandleMenuMsg is defined as HRESULT HandleMenuMsg(UINT uMsg, WPARAM wParam, LPARAM lParam); In c# i'd probably make that [PreserveSig] int HandleMenuMsg(uint uMsg, IntPtr wParam,IntPtr lParam); though of course i'd have to look up the header definitions of LPARAM and WPARAM to be certain of their size/type. Without PreserveSig that would return void instead of int and if you have an error you'll have to throw an exception with an hresul generated using the Marshal class functions. In my limited experience if you do something wrong with your marshalling you end up corrupting the shell memory and eventually it'll either start to behave very oddly or it'll just crash unexpectedly.

          L 1 Reply Last reply
          0
          • W Wraith2

            Can you privode a link, or tell me how to find that definition you used? Because it seems to be contrary to the documentation i've read. I also couln'dt find a useful implementation of IContextMenu and provided my own. While i cant claim its perfect i've not had any problems with the shell crashing in quite a while now so i think i'm at or close to a correct definition. I'd also be interested to see those articles, i've read around COM interop articles a bit lately and i've not found any that specifically mentioned the redefinition argument. IContextMenu2.HandleMenuMsg is defined as HRESULT HandleMenuMsg(UINT uMsg, WPARAM wParam, LPARAM lParam); In c# i'd probably make that [PreserveSig] int HandleMenuMsg(uint uMsg, IntPtr wParam,IntPtr lParam); though of course i'd have to look up the header definitions of LPARAM and WPARAM to be certain of their size/type. Without PreserveSig that would return void instead of int and if you have an error you'll have to throw an exception with an hresul generated using the Marshal class functions. In my limited experience if you do something wrong with your marshalling you end up corrupting the shell memory and eventually it'll either start to behave very oddly or it'll just crash unexpectedly.

            L Offline
            L Offline
            LoKi_za
            wrote on last edited by
            #5

            I've defined the HandleMenuMsg the same. The article about redefinition is here: http://www.dotnet247.com/247reference/msgs/28/140482.aspx >:)

            W 1 Reply Last reply
            0
            • L LoKi_za

              I've defined the HandleMenuMsg the same. The article about redefinition is here: http://www.dotnet247.com/247reference/msgs/28/140482.aspx >:)

              W Offline
              W Offline
              Wraith2
              wrote on last edited by
              #6

              Interesting, Mattias Sjögren is very knowledgable about these things. I've come across posts of his many times. The first thing that struck me was that the order of your methods doesn't match the example at the end of the discussion. COM methods have a defined order, if you change the order it won't work so well. If you look at the c or c++ definitions of the itnerfaces in the PSDK you'll find the correct order to use, this is also usually the order used in the documentation but its always worth checking to make sure. Make sure they are in the order IUnknown (implicitly added so don't bother), IContextMenu, IContextMenu2. I'm no expert on COM, the shell interfaces are really my first try, but i've picked up a few things on the way through the docs. I think i'm being lucky and a bit cheeky with my definitions and that its working because the COM interop has to interpret the exported methods into a vtable rather than building it at compile time. I'm going to have a tinker with IContextMenu2 and IContextMenu3 and see what happens later. I do remember reading an article (possibly here ar codeproject) which states that you don't have ti implement inherited interfaces in the using interface but i'm more certain that Mattias is correct.

              L 1 Reply Last reply
              0
              • W Wraith2

                Interesting, Mattias Sjögren is very knowledgable about these things. I've come across posts of his many times. The first thing that struck me was that the order of your methods doesn't match the example at the end of the discussion. COM methods have a defined order, if you change the order it won't work so well. If you look at the c or c++ definitions of the itnerfaces in the PSDK you'll find the correct order to use, this is also usually the order used in the documentation but its always worth checking to make sure. Make sure they are in the order IUnknown (implicitly added so don't bother), IContextMenu, IContextMenu2. I'm no expert on COM, the shell interfaces are really my first try, but i've picked up a few things on the way through the docs. I think i'm being lucky and a bit cheeky with my definitions and that its working because the COM interop has to interpret the exported methods into a vtable rather than building it at compile time. I'm going to have a tinker with IContextMenu2 and IContextMenu3 and see what happens later. I do remember reading an article (possibly here ar codeproject) which states that you don't have ti implement inherited interfaces in the using interface but i'm more certain that Mattias is correct.

                L Offline
                L Offline
                LoKi_za
                wrote on last edited by
                #7

                WRT the ordering, if I put HandleMenuMsg at the bottom of the decleration, it doesn't receive windows messages. >:)

                W 1 Reply Last reply
                0
                • L LoKi_za

                  WRT the ordering, if I put HandleMenuMsg at the bottom of the decleration, it doesn't receive windows messages. >:)

                  W Offline
                  W Offline
                  Wraith2
                  wrote on last edited by
                  #8

                  But does it crash? Because not getting any messages may be the correct behavior while crashign certainly isn't.

                  L 1 Reply Last reply
                  0
                  • W Wraith2

                    But does it crash? Because not getting any messages may be the correct behavior while crashign certainly isn't.

                    L Offline
                    L Offline
                    LoKi_za
                    wrote on last edited by
                    #9

                    The method should receive a call when the context menu is activated via explorer. When it does receive a call, it receives the Msg, LParam and WParam no problems, but crashes shortly thereafter with a memory fault (explorer.exe - Application Error. Instruction at "0x78312aa5" referenced memory at "0x00000028". Memory could not be "read".) and subsequently shuts down the explorer window (not the process). >:)

                    W 1 Reply Last reply
                    0
                    • L LoKi_za

                      The method should receive a call when the context menu is activated via explorer. When it does receive a call, it receives the Msg, LParam and WParam no problems, but crashes shortly thereafter with a memory fault (explorer.exe - Application Error. Instruction at "0x78312aa5" referenced memory at "0x00000028". Memory could not be "read".) and subsequently shuts down the explorer window (not the process). >:)

                      W Offline
                      W Offline
                      Wraith2
                      wrote on last edited by
                      #10

                      Personally i define crashing as an error condition, and one of the bigger ones as well. I realize that HandleMenuMsg should be called but it should also not cause the hosting application to crash. If you look at the definitions of ContextMenu, 2 and 3 in ShlObj.h the methods are specified in a specific and exact order. When the runtime interop does its work it doesn't have a lookup table of method names, it puts the methods in the order they are in the class/interface. If you've got them in the wrong order they wrong method could be called. Put them in the right order and then go back and read through what is required for IContextMenu2 to run, perhaps a precondition isn't being met, perhaps a marshalling error is occuring before your function body is reached. Perhaps it is wrong in some way, but at least you'll know that the right method is being called with the right parameters at the right time if it ever is called.

                      1 Reply Last reply
                      0
                      Reply
                      • Reply as topic
                      Log in to reply
                      • Oldest to Newest
                      • Newest to Oldest
                      • Most Votes


                      • Login

                      • Don't have an account? Register

                      • Login or register to search.
                      • First post
                        Last post
                      0
                      • Categories
                      • Recent
                      • Tags
                      • Popular
                      • World
                      • Users
                      • Groups