{"id":1938,"date":"2013-10-16T20:48:51","date_gmt":"2013-10-16T08:48:51","guid":{"rendered":"https:\/\/www.deltics.co.nz\/blog\/?p=1938"},"modified":"2013-10-16T20:58:45","modified_gmt":"2013-10-16T08:58:45","slug":"menu-items-apis-crackers-and-hackers","status":"publish","type":"post","link":"https:\/\/www.deltics.co.nz\/blog\/posts\/1938\/","title":{"rendered":"Menu Items, APIs, Crackers and Hackers"},"content":{"rendered":"<span class=\"rt-reading-time\" style=\"display: block;\"><span class=\"rt-label rt-prefix\">[Estimated Reading Time: <\/span> <span class=\"rt-time\">4<\/span> <span class=\"rt-label rt-postfix\">minutes]<\/span><\/span><p>Francois Piette recently posted a solution to <a href=\"http:\/\/francois-piette.blogspot.co.nz\/2013\/10\/where-is-that-menuitem-displayed.html\">obtaining the screen position of a menu item involving using a &#8220;hacker&#8221; class<\/a>.  There is however a safer, more direct mechanism which I hope Francois won&#8217;t mind me sharing and a far <em>less<\/em> safe related hacking technique that his post brought to mind.<\/p>\n<p><!--more--><\/p>\n<h2>A Puzzle Wrapped in an Enigma<\/h2>\n<p>Francois&#8217; original puzzle was an interesting one to solve:  how to determine the position on screen of a given menu item.  I have to say first initial instinct was to think that the <strong>Windows API<\/strong> must provide access to this information more directly.<\/p>\n<p>And it does.  \ud83d\ude42<\/p>\n<p>To obtain the screen co-ordinates of a menu item you can simply call the <strong><a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/windows\/desktop\/ms647981(v=vs.85).aspx\">GetMenuItemRect<\/a>()<\/strong> API in <strong>Windows<\/strong>.  All you need is the <strong>HMENU<\/strong> of the menu and the index of the item of interest.<\/p>\n<p>For reliable position information the menu item should be visible, which is of course going to be the case if you call this API in response to an <strong>OnClick<\/strong> of the menu item in question.<\/p>\n<p>Here&#8217;s a revised version of Francois example with a simple form which presents a modal version of itself at the position of either of two menu items on the <strong>File1<\/strong> menu (<strong>FileItem1<\/strong> and <strong>FileItem2<\/strong> both share the <strong>FileItemClick<\/strong> event): <\/p>\n<pre class=\"brush: delphi; title: ; notranslate\" title=\"\">\r\nunit Unit1;\r\n\r\ninterface\r\n\r\nuses\r\n  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,\r\n  Dialogs, Menus;\r\n\r\ntype\r\n  TForm1 = class(TForm)\r\n    MainMenu1: TMainMenu;\r\n    File1: TMenuItem;\r\n    FileItem1: TMenuItem;\r\n    FileItem2: TMenuItem;\r\n    Close1: TMenuItem;\r\n    procedure FileItemClick(Sender: TObject);\r\n    procedure Close1Click(Sender: TObject);\r\n  private\r\n    { Private declarations }\r\n  public\r\n    { Public declarations }\r\n  end;\r\n\r\nvar\r\n  Form1: TForm1;\r\n\r\nimplementation\r\n\r\n{$R *.dfm}\r\n\r\nprocedure TForm1.Close1Click(Sender: TObject);\r\nbegin\r\n  ModalResult := mrOk;\r\nend;\r\n\r\nprocedure TForm1.FileItemClick(Sender: TObject);\r\nvar\r\n  rc: TRect;\r\n  form: TForm1;\r\nbegin\r\n  GetMenuItemRect(Handle, File1.Handle, File1.IndexOf(TMenuItem(Sender)), rc);\r\n\r\n  form := TForm1.Create(self);\r\n  form.Left := rc.Left;\r\n  form.Top  := rc.Top;\r\n  form.ShowModal;\r\nend;\r\n<\/pre>\n<p>There&#8217;s no attempt to code this correctly &#8211; freeing the modal forms properly etc.  The point is the menu item rectangle determination.<\/p>\n<p>Which isn&#8217;t to say that Francois&#8217; hacker class technique doesn&#8217;t have it&#8217;s uses.  It absolutely does, in Delphi.<\/p>\n<p>Apart from anything else, it is an alternative to &#8220;class helpers&#8221; that is not vulnerable to <a href=\"https:\/\/www.deltics.co.nz\/blog\/posts\/282\">the &#8220;<em>Highlander<\/em>&#8221; constraint constraint those suffer from (&#8220;<em>There can be only one<\/em> [in scope]&#8221;)<\/a>.<\/p>\n<p>But Francois&#8217; post also stirred a distant memory of a related technique.<\/p>\n<h2>Hackers vs Crackers<\/h2>\n<p>Francois calls his sub-class a &#8220;hacker&#8221;.  I prefer to call classes that exploit this particular &#8220;protected extension&#8221; behaviour &#8220;crackers&#8221;, since they &#8220;crack open&#8221; a class for access to protected members but are otherwise entirely safe.<\/p>\n<p>After all, they are more or less formally supported &#8211; though less well imho &#8211; by &#8220;class helpers&#8221;.<\/p>\n<p>I do have another type of class which I term a &#8220;hacker&#8221;, which is far, far <strong>less<\/strong> safe (<strong>diabolically unsafe<\/strong> would be nearer the mark) since they provide access to the <strong>private<\/strong> members of some other class.  Furthermore, classes exploiting this technique are vulnerable to changes in the &#8220;target&#8221; class in different Delphi versions.<\/p>\n<p>You start by declaring a class but in this case instead of the <em>target<\/em> class you derive from the target class&#8217; own <em>ancestor<\/em>.<\/p>\n<p>So, to hack a <strong>TMenuItem<\/strong> you would extend <strong>TComponent<\/strong> since this is the class that <strong>TMenuItem<\/strong> extends:<\/p>\n<pre class=\"brush: delphi; title: ; notranslate\" title=\"\">\r\n  TMenuItemHack = class(TComponent)\r\n<\/pre>\n<p>You then reproduce, verbatim, the member declarations of the target class, down to and including any private member you wish to gain access to.  For the sake of argument let&#8217;s assume we wanted to directly access the <strong>FRadioItem<\/strong> private member of a <strong>TMenuItem<\/strong> (this is a purely hypothetical example):<\/p>\n<pre class=\"brush: delphi; title: ; notranslate\" title=\"\">\r\n  TMenuItemHack = class(TComponent)\r\n  private\r\n    FCaption: string;\r\n    FChecked: Boolean;\r\n    FEnabled: Boolean;\r\n    FDefault: Boolean;\r\n    FAutoHotkeys: TMenuItemAutoFlag;\r\n    FAutoLineReduction: TMenuItemAutoFlag;\r\n    FRadioItem: Boolean;\r\n  end;\r\n<\/pre>\n<p>Assuming you have a correctly declared hack class, you can now use this class to type-cast a reference to an instance of the target class and thus directly access the <strong>private<\/strong> members up to and including the last one declared.<\/p>\n<pre class=\"brush: delphi; title: ; notranslate\" title=\"\">\r\n  isDefault := TMenuItemHack(SomeMenuItem).fDefault;\r\n\r\n  TMenuItemHack(SomeMenuItem).fDefault := FALSE;\r\n<\/pre>\n<p>If you place the hack class in a unit other than the unit where it is used, you will need to change <strong>private<\/strong> or <strong>protected<\/strong> visibility specifiers to <strong>public<\/strong> for the member(s) of interest.<\/p>\n<p>As I say, this is <em>highly<\/em> sensitive to Delphi versions.  This is the declaration from <strong>Delphi 2010<\/strong>, which may be the same in a number of other Delphi versions, possibly all.  But if the member declarations of your target class vary in order or content in some other version then you must reflect those variations in the declaration when compiling using those other versions.<\/p>\n<p>Based on experience of this technique in the past*, you can omit any function or procedure declarations even if they occur between member variables.  All that seems to matter is that you have all the member variables themselves.<\/p>\n<p>(* &#8211; <em>don&#8217;t ask.  It was on a project a joined and, to be fair, as unsavoury as it is it was necessary in that case with that particular version of Delphi to enable a particular behaviour in the application<\/em>)<\/p>\n<p>It is also potentially vulnerable to variations in compiler behavior that may impact on the member layout of class member variables.  This is perhaps unlikely, though it is possible (though again, not something I have encountered) that the declarations in the VCL source do not correspond to the actual declarations in the pre-compiled VCL unit that the compiler will use (unless you have contrived to redirect the compiler to your own copy of that unit, which is a whole other minefield!).<\/p>\n<p>As I say, the technique is utterly unsafe and relies on the memory layout of two classes with the same ancestor and the same member variable declarations being identical.  The &#8220;hack&#8221; class is &#8211; in effect &#8211; overlayed on top of the memory of an instance of the target class.<\/p>\n<p>You really are digging around in the guts &#8211; the physical memory &#8211; of the target instance, and if you get it even slightly wrong there is no telling what the impact might be.<\/p>\n<p>But it can be a life saver if you absolutely must gain access to some private member that is not exposed in a way that you need.<\/p>\n","protected":false},"excerpt":{"rendered":"<p><span class=\"rt-reading-time\" style=\"display: block;\"><span class=\"rt-label rt-prefix\">[Estimated Reading Time: <\/span> <span class=\"rt-time\">4<\/span> <span class=\"rt-label rt-postfix\">minutes]<\/span><\/span> Francois Piette recently posted a solution to obtaining the screen position of a menu item involving using a &#8220;hacker&#8221; class. There is however a safer, more direct mechanism which I hope Francois won&#8217;t mind me sharing and a far less safe related hacking technique that his post brought to mind.<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"jetpack_publicize_message":"","jetpack_is_tweetstorm":false,"jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":[]},"categories":[4],"tags":[244,245,52,292,13],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/p1TKYv-vg","jetpack_sharing_enabled":true,"jetpack-related-posts":[{"id":1658,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/1658\/","url_meta":{"origin":1938,"position":0},"title":"Crash Bang Wallop, What a Picture!","date":"19 Sep 2013","format":false,"excerpt":"The fourth and final part in the not-as-short-as-I-thought-it-would be series on building a camera app for Android using Oxygene. In this penultimate instalment we will add the capability to actually take a picture. But that won't take very long, so then we will spend a bit of time tidying up\u2026","rel":"","context":"In &quot;Android&quot;","img":{"alt_text":"Very Ugly Duckling","src":"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screenshot_2013-09-19-19-38-56-1024x640.jpg?resize=350%2C200&ssl=1","width":350,"height":200},"classes":[]},{"id":606,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/606\/","url_meta":{"origin":1938,"position":1},"title":"Learning Experiences &#8211; Moving The Execution Point Pre-Delphi 2010","date":"18 Oct 2009","format":false,"excerpt":"Thanks to commenters I have already learned two useful things as a result of yesterday's post, both things which I cannot fathom how I did not already know. \u00a0But here's something I learned for myself as a result of a comment made by Malcolm Groves at the Auckland Delphi 2010\u2026","rel":"","context":"In &quot;Delphi&quot;","img":{"alt_text":"","src":"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/New-EIP-300x286.jpg?resize=350%2C200&ssl=1","width":350,"height":200},"classes":[]},{"id":2086,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/2086\/","url_meta":{"origin":1938,"position":2},"title":"ADB WINLOG 1.0.1 &#8211; RELEASED!","date":"04 Nov 2013","format":false,"excerpt":"Are you doing Android development ? Whether you are using Delphi or some other Android development tool a key tool in the Android developer's toolbox is the logcat command, part of the Android SDK. But it can be a little... how to put this kindly... crude. So I put together\u2026","rel":"","context":"In &quot;Android&quot;","img":{"alt_text":"ADB WINLOG 1.0.1","src":"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2013-11-03-at-19.56.37-.png?resize=350%2C200&ssl=1","width":350,"height":200},"classes":[]},{"id":825,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/825\/","url_meta":{"origin":1938,"position":3},"title":"Class Helpers &#8211; A Hackers Cloak of Respectability","date":"09 Nov 2011","format":false,"excerpt":"Mat DeLong just posted another great example of when not to abuse class helpers in Delphi (though I should add that he didn't seem to see it that way). :) But you don't need helpers to do what this technique achieves, and in my view you really shouldn't be using\u2026","rel":"","context":"In &quot;Delphi&quot;","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":2511,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/2511\/","url_meta":{"origin":1938,"position":4},"title":"Anonymous Classes: Implementing Interfaces","date":"11 Feb 2017","format":false,"excerpt":"A few years ago (2011 to be precise) someone asked a question on StackOverflow about support for anonymous classes in Delphi. The reason for the question was that the poster was trying to use Delphi to develop for Android and on that platform the widespread use of callback interfaces makes\u2026","rel":"","context":"In &quot;Android&quot;","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":295,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/295\/","url_meta":{"origin":1938,"position":5},"title":"Making A Splash","date":"04 Sep 2008","format":false,"excerpt":"OK, so who hasn't done this a million times - adding a splash screen to a Delphi application.\u00a0 I've seen any number of \"easy\" ways to do this but during a session at Tech Ed '08 this week I saw the latest in splash screen technology from Microsoft:\u00a0 A SplashScreen\u2026","rel":"","context":"In &quot;Delphi&quot;","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]}],"_links":{"self":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts\/1938"}],"collection":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/comments?post=1938"}],"version-history":[{"count":3,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts\/1938\/revisions"}],"predecessor-version":[{"id":1942,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts\/1938\/revisions\/1942"}],"wp:attachment":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/media?parent=1938"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/categories?post=1938"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/tags?post=1938"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}