{"id":40723,"date":"2004-02-06T07:00:00","date_gmt":"2004-02-06T07:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2004\/02\/06\/adjustor-thunks\/"},"modified":"2004-02-06T07:00:00","modified_gmt":"2004-02-06T07:00:00","slug":"adjustor-thunks","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20040206-00\/?p=40723","title":{"rendered":"Adjustor thunks"},"content":{"rendered":"<p>\n<a HREF=\"http:\/\/weblogs.asp.net\/oldnewthing\/archive\/2004\/02\/05\/68017.aspx\">\nYesterday we learned about the layout of COM objects<\/a> and I\nhinted at &#8220;adjustor thunks&#8221;.<\/p>\n<p>\nIf you find yourself debugging in disassembly,\nyou&#8217;ll sometimes find strange little functions called\n&#8220;adjustor thunks&#8221;.\nLet&#8217;s take another look at the object we laid out last time:\n<\/p>\n<pre>\nclass CSample : public IPersist, public IServiceProvider\n{\npublic:\n  \/\/ *** IUnknown ***\n  STDMETHODIMP QueryInterface(REFIID riid, void** ppv);\n  STDMETHODIMP_(ULONG) AddRef();\n  STDMETHODIMP_(ULONG) Release();\n  \/\/ *** IPersist ***\n  STDMETHODIMP GetClassID(CLSID* pClassID);\n  \/\/ *** IQueryService ***\n  STDMETHODIMP QueryService(REFGUID guidService,\n                  REFIID riid, void** ppv);\nprivate:\n  LONG m_cRef;\n  ...\n};\n<\/pre>\n<table BORDER=\"0\">\n<col SPAN=\"7\" ALIGN=\"center\">\n<tr>\n<td>p<\/td>\n<td>&rarr;<\/td>\n<td STYLE=\"border: solid 1px buttonshadow\">&nbsp; &nbsp;lpVtbl&nbsp; &nbsp;<\/td>\n<td>&rarr;<\/td>\n<td ALIGN=\"center\">&rarr;<\/td>\n<td>&rarr;<\/td>\n<td STYLE=\"border: solid 1px buttonshadow;height: 2em\">QueryInterface (1)<\/td>\n<\/tr>\n<tr>\n<td>q<\/td>\n<td>&rarr;<\/td>\n<td STYLE=\"border: solid 1px buttonshadow\">&nbsp; &nbsp;lpVtbl&nbsp; &nbsp;<\/td>\n<td>&rarr;<\/td>\n<td STYLE=\"border: solid 1px buttonshadow;height: 2em\">QueryInterface (2)<\/td>\n<td ROWSPAN=\"4\"><span STYLE=\"width: 2em\"><\/span><\/td>\n<td STYLE=\"border: solid 1px buttonshadow;height: 2em\">AddRef (1)<\/td>\n<\/tr>\n<tr>\n<td ROWSPAN=\"3\" COLSPAN=\"2\"><\/td>\n<td STYLE=\"border: solid 1px buttonshadow\">m_cRef<\/td>\n<td ROWSPAN=\"3\"><\/td>\n<td STYLE=\"border: solid 1px buttonshadow;height: 2em\">AddRef (2)<\/td>\n<td STYLE=\"border: solid 1px buttonshadow;height: 2em\">Release (1)<\/td>\n<\/tr>\n<tr>\n<td STYLE=\"border: solid 1px buttonshadow\">&#8230;<\/td>\n<td STYLE=\"border: solid 1px buttonshadow;height: 2em\">Release (2)<\/td>\n<td STYLE=\"border: solid 1px buttonshadow;height: 2em\">GetClassID (1)<\/td>\n<\/tr>\n<tr>\n<td><\/td>\n<td STYLE=\"border: solid 1px buttonshadow;height: 2em\">QueryService (2)<\/td>\n<\/tr>\n<\/table>\n<p>\nIn the diagram, p is the pointer returned when the IPersist interface\nis needed, and q is the pointer for the IQueryService interface.\n<\/p>\n<p>\nNow, there is only one QueryInterface method, but there are two entries,\none for each vtable.  Remember that each function in a vtable receives\nthe corresponding interface pointer as its &#8220;this&#8221; parameter.  That&#8217;s\njust fine for QueryInterface&nbsp;(1); its interface pointer is the\nsame as the object&#8217;s interface pointer.  But that&#8217;s bad news for\nQueryInterface&nbsp;(2), since its interface pointer is q, not p.\n<\/p>\n<p>\nThis is where the adjustor thunks come in.\n<\/p>\n<p>\nThe entry for QueryInterface&nbsp;(2) is a stub function that\nchanges q to p, and then lets QueryInterface&nbsp;(1) do the\nrest of the work. This stub function is the adjustor thunk.\n<\/p>\n<pre>\n[thunk]:CSample::QueryInterface`adjustor{4}':\n  sub     DWORD PTR [esp+4], 4 ; this -= sizeof(lpVtbl)\n  jmp     CSample::QueryInterface\n<\/pre>\n<p>\nThe adjustor thunk takes the &#8220;this&#8221; pointer and subtracts 4,\nconverting q into p, then it jumps to the QueryInterface&nbsp;(1)\nfunction to do the real work.\n<\/p>\n<p>Whenever you have multiple inheritance and a virtual function is\nimplemented on multiple base classes, you will get an\nadjustor thunk for the second and subsequent base\nclass methods in order to convert the &#8220;this&#8221; pointer into a common\nformat.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Yesterday we learned about the layout of COM objects and I hinted at &#8220;adjustor thunks&#8221;. If you find yourself debugging in disassembly, you&#8217;ll sometimes find strange little functions called &#8220;adjustor thunks&#8221;. Let&#8217;s take another look at the object we laid out last time: class CSample : public IPersist, public IServiceProvider { public: \/\/ *** IUnknown [&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":[2],"class_list":["post-40723","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-history"],"acf":[],"blog_post_summary":"<p>Yesterday we learned about the layout of COM objects and I hinted at &#8220;adjustor thunks&#8221;. If you find yourself debugging in disassembly, you&#8217;ll sometimes find strange little functions called &#8220;adjustor thunks&#8221;. Let&#8217;s take another look at the object we laid out last time: class CSample : public IPersist, public IServiceProvider { public: \/\/ *** IUnknown [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/40723","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=40723"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/40723\/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=40723"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=40723"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=40723"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}