{"id":5383,"date":"2013-02-01T07:00:00","date_gmt":"2013-02-01T07:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2013\/02\/01\/psychic-debugging-why-your-icontextmenuinvokecommand-doesnt-get-called-even-though-you-returned-success-from-icontextmenuquerycontextmenu\/"},"modified":"2013-02-01T07:00:00","modified_gmt":"2013-02-01T07:00:00","slug":"psychic-debugging-why-your-icontextmenuinvokecommand-doesnt-get-called-even-though-you-returned-success-from-icontextmenuquerycontextmenu","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20130201-00\/?p=5383","title":{"rendered":"Psychic debugging: Why your IContextMenu::InvokeCommand doesn&#8217;t get called even though you returned success from IContextMenu::QueryContextMenu"},"content":{"rendered":"<p><P>\nA customer was having trouble with their\n<CODE>IContext&shy;Menu<\/CODE> implementation.\nThey observed that their\n<CODE>IContext&shy;Menu::Query&shy;Context&shy;Menu<\/CODE> method\nwas being called,\nbut when the user selected their menu item,\n<CODE>IContext&shy;Menu::Invoke&shy;Command<\/CODE> was\nnot being called.\n<\/P>\n<P>\nGiven what you know about shell context menus,\nyou can already direct the investigation.\nI&#8217;ll let you\n<A HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2004\/09\/20\/231739.aspx\">\nread up about it first<\/A>,\n<A HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2004\/10\/07\/239197.aspx\">\nespecially the part about composition<\/A>,\nthen we can see how much you&#8217;ve learned.\n<\/P>\n<P>\nWelcome back.\n(Okay, I know you didn&#8217;t actually do the reading,\nbut I&#8217;m welcoming you back anyway.)\n<\/P>\n<P>\nYour first theory as to why\n<CODE>IContext&shy;Menu::Invoke&shy;Command<\/CODE> is\nnot being called is probably\nthat they returned <CODE>S_OK<\/CODE> from\n<CODE>IContext&shy;Menu::Query&shy;Context&shy;Menu<\/CODE> instead\nof\n<CODE>MAKE_HRESULT(SEVERITY_SUCCESS,\nFACILITY_NULL, 1)<\/CODE>.\nThat would explain the problem, because a return value of\n<CODE>S_OK<\/CODE>\nis equivalent to\n<CODE>MAKE_HRESULT(SEVERITY_SUCCESS,\nFACILITY_NULL, 0)<\/CODE>,\nwhich means\n&#8220;I successfully added up to zero menu items starting at\n<CODE>idCmd&shy;First<\/CODE>.&#8221;\nWhen the user picks the menu item they added,\nthe dispatcher will go looking for the corresponding\ncomposite menu component,\nand since they said that they used zero entries,\nthey will naturally never be called,\nsince they disavowed any responsibility for those items.\n<\/P>\n<P>\n&#8220;Nope, that&#8217;s not it.\nWe&#8217;re returning\n<CODE>MAKE_HRESULT(SEVERITY_SUCCESS,\nFACILITY_NULL, 1)<\/CODE>.\nAny other guesses?&#8221;\n<\/P>\n<P>\nOh great, the customer is now playing Twenty Questions.\n<\/P>\n<P>\n&#8220;I&#8217;m going to pose a puzzle with almost no clues,\nand you get to propose solutions,\nand I&#8217;ll say whether or not you&#8217;re right.&#8221;\n<\/P>\n<P>\nI don&#8217;t know why customers play this game.\nMaybe they don&#8217;t realize that asking for help via email\nis very different from asking for help face-to-face.\nIn a face-to-face conversation,\nthe answer to a question arrives within seconds,\nwhereas in email it can take hours or days.\nThis means that when the answer finally comes back,\nthe person asking the question has\nto go back and read the conversation history\nthread to re-establish context.\n<\/P>\n<P>\nOr maybe they think they&#8217;re going to be disclosing\nTop Secret Information to Microsoft if they\nshare the code that they can&#8217;t get to work.\nTrust me, we don&#8217;t care about your Top Secret Algorithm\nfor Beating the Stock Market With No Money Down.\nGo ahead and remove those from the code.\nWe just want to see how you are interfacing with the shell.\n(And besides, you probably should be removing them anyway,\nsince they are irrelevant and are not part\nof a minimal program that reproduces the problem.)\n<\/P>\n<P>\nWhat would your next guess be?\n<\/P>\n<P>\n&#8220;Perhaps you&#8217;re adding your items with the wrong menu item ID.&#8221;\nThat would explain the problem,\nbecause returning\n<CODE>MAKE_HRESULT(SEVERITY_SUCCESS,\nFACILITY_NULL, 1)<\/CODE>\nmeans\n&#8220;I successfully added up to one menu item starting at\n<CODE>idCmd&shy;First<\/CODE>.&#8221;\nBut if they didn&#8217;t actually add it at <CODE>idCmd&shy;First<\/CODE>,\nthen when the user selects the item,\nit won&#8217;t be in the range they claimed,\nand therefore the invoke won&#8217;t get routed to them.\n<\/P>\n<P>\n&#8220;Your intuition is wrong again.\nHere&#8217;s the code we&#8217;re using.&#8221;\n<\/P>\n<P>\nI can abide by the &#8220;Ha ha, you guessed wrong again!&#8221;\nbecause it at least prodded them into sharing some code.\nNot much code, mind you, but at least some.\n<\/P>\n<PRE>\nHRESULT SooperSeekrit::QueryContextMenu(\n    HMENU hmenu,\n    UINT indexMenu,\n    UINT idCmdFirst,\n    UINT idCmdLast,\n    UINT uFlags)\n{\n  UINT cItemsAdded = 0;\n  if (!(uFlags &amp; CMF_DEFAULTONLY) &amp;&amp;\n      InsertMenuItem(hmenu,\n                     indexMenu,\n                     TRUE,\n                     &amp;globalMenuItemInfo)) {\n    return MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, 1);\n  }\n  return MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, 0);\n}\n<\/PRE>\n<P>\nThe next thing you should have noticed is that they\nnever actually used the\n<CODE>idCmd&shy;First<\/CODE> parameter.\nSo how could they claim to be adding the items with the correct\nmenu item ID if they ignore the variable that tells them what\nthe correct menu item ID is?\n<\/P>\n<P>\n&#8220;Could you tell us more about the\n<CODE>global&shy;Menu&shy;Item&shy;Info<\/CODE>\nvariable?\nIn particular, what value does it use for the <CODE>wID<\/CODE> member,\nand how do you make sure that it is equal to\n<CODE>idCmd&shy;First<\/CODE>?\nIt seems that you are missing some lines of code here:\n<\/P>\n<PRE>\nglobalMenuItemInfo.fMask |= MIIM_ID;\nglobalMenuItemInfo.wID = idCmdFirst;\n<\/PRE>\n<P>\nbut perhaps there&#8217;s something going on that we are missing.&#8221;\n<\/P>\n<P>\nThe customer cheerfully replied,\n&#8220;Oops, sorry, didn&#8217;t notice that.\nWorks great now, thanks!&#8221;\n<\/P>\n<P>\nI didn&#8217;t bother to draw their attention to the fact that they\nlied when they responded to the question\n&#8220;Did you add the menu item with the correct ID?&#8221;\nwith &#8220;Wrong again! BZZZT!&#8221;\n<\/P>\n<P>\nThe point of today&#8217;s story is that you, gentle reader,\nalready know how to debug these types of issues.\nYou just have to take what you know and apply it to the situation\nat hand.\nIf you know how composite context menu dispatch works,\nthen you can come up with failure modes in which the dispatcher\nfails to match up the menu item with the component.\n<\/P>\n<P>\n<B>Exercise<\/B>:\nThe customer is still not out of the woods yet.\nWhat other bug remains in their\n<CODE>IContext&shy;Menu::Query&shy;Context&shy;Menu<\/CODE>\nimplementation?\n<\/P><\/p>\n","protected":false},"excerpt":{"rendered":"<p>A customer was having trouble with their IContext&shy;Menu implementation. They observed that their IContext&shy;Menu::Query&shy;Context&shy;Menu method was being called, but when the user selected their menu item, IContext&shy;Menu::Invoke&shy;Command was not being called. Given what you know about shell context menus, you can already direct the investigation. I&#8217;ll let you read up about it first, especially the [&hellip;]<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-5383","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>A customer was having trouble with their IContext&shy;Menu implementation. They observed that their IContext&shy;Menu::Query&shy;Context&shy;Menu method was being called, but when the user selected their menu item, IContext&shy;Menu::Invoke&shy;Command was not being called. Given what you know about shell context menus, you can already direct the investigation. I&#8217;ll let you read up about it first, especially the [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/5383","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=5383"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/5383\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=5383"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=5383"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=5383"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}