{"id":40733,"date":"2004-02-05T07:00:00","date_gmt":"2004-02-05T07:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2004\/02\/05\/the-layout-of-a-com-object\/"},"modified":"2004-02-05T07:00:00","modified_gmt":"2004-02-05T07:00:00","slug":"the-layout-of-a-com-object","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20040205-00\/?p=40733","title":{"rendered":"The layout of a COM object"},"content":{"rendered":"<p>\nThe Win32 COM calling convention specifies the layout of\nthe virtual method table (vtable) of an object.\nIf a language\/compiler wants to support COM, it must lay\nout its object in the specified manner so other components\ncan use it.<\/p>\n<p>\nIt is no coincidence that the Win32 COM object layout matches\nclosely the C++ object layout.  Even though COM was originally\ndeveloped when C was the predominant programming language,\nthe designers saw fit to &#8220;play friendly&#8221; with the up-and-coming\nnew language C++.\n<\/p>\n<p>\nThe layout of a COM object is made explicit in the header files\nfor the various\ninterfaces. For example, here&#8217;s IPersist from objidl.h, after cleaning\nup some macros.<\/p>\n<pre>\ntypedef struct IPersistVtbl\n{\n    HRESULT ( STDMETHODCALLTYPE *QueryInterface )(\n        IPersist * This,\n        \/* [in] *\/ REFIID riid,\n        \/* [iid_is][out] *\/ void **ppvObject);\n    ULONG ( STDMETHODCALLTYPE *AddRef )(\n        IPersist * This);\n    ULONG ( STDMETHODCALLTYPE *Release )(\n        IPersist * This);\n    HRESULT ( STDMETHODCALLTYPE *GetClassID )(\n        IPersist * This,\n        \/* [out] *\/ CLSID *pClassID);\n} IPersistVtbl;\nstruct IPersist\n{\n    const struct IPersistVtbl *lpVtbl;\n};\n<\/pre>\n<p>\nThis corresponds to the following memory layout:\n<\/p>\n<table BORDER=\"0\" CELLSPACING=\"0\" CELLPADDING=\"0\" STYLE=\"border-collapse: collapse\">\n<col SPAN=\"5\" 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 STYLE=\"border: solid 1px buttonshadow;height: 2em\">QueryInterface<\/td>\n<\/tr>\n<tr>\n<td ROWSPAN=\"3\"><\/td>\n<td ROWSPAN=\"3\"><\/td>\n<td ROWSPAN=\"3\"><\/td>\n<td ROWSPAN=\"3\"><\/td>\n<td STYLE=\"border: solid 1px buttonshadow;height: 2em\">AddRef<\/td>\n<\/tr>\n<tr>\n<td STYLE=\"border: solid 1px buttonshadow;height: 2em\">Release<\/td>\n<\/tr>\n<tr>\n<td STYLE=\"border: solid 1px buttonshadow;height: 2em\">GetClassID<\/td>\n<\/tr>\n<\/table>\n<p>\nWhat does this mean?\n<\/p>\n<p>\nA COM interface pointer is a pointer to a structure that consists\nof just a vtable.\nThe vtable is a structure that contains a bunch of function pointers.\nEach function in the list takes that interface pointer (p) as its first\nparameter (&#8220;this&#8221;).\n<\/p>\n<p>\nThe magic to all this is that since your function gets p\nas its first parameter, you can &#8220;hang&#8221; additional\nstuff onto that vtable:\n<\/p>\n<table BORDER=\"0\" CELLSPACING=\"0\" CELLPADDING=\"0\" STYLE=\"border-collapse: collapse\">\n<col SPAN=\"5\" 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 STYLE=\"border: solid 1px buttonshadow;height: 2em\">QueryInterface<\/td>\n<\/tr>\n<tr>\n<td ROWSPAN=\"3\"><\/td>\n<td ROWSPAN=\"3\"><\/td>\n<td ROWSPAN=\"3\" STYLE=\"border: solid 1px buttonshadow\">&#8230;<br \/>\n          other stuff<br \/>&#8230;<\/td>\n<td ROWSPAN=\"3\"><\/td>\n<td STYLE=\"border: solid 1px buttonshadow;height: 2em\">AddRef<\/td>\n<\/tr>\n<tr>\n<td STYLE=\"border: solid 1px buttonshadow;height: 2em\">Release<\/td>\n<\/tr>\n<tr>\n<td STYLE=\"border: solid 1px buttonshadow;height: 2em\">GetClassID<\/td>\n<\/tr>\n<\/table>\n<p>\nThe functions in the vtable can use offsets relative to the\ninterface pointer to access its other stuff.\n<\/p>\n<p>\nIf an object implements multiple interfaces but they are all descendants\nof each other, then a single vtable can be used for all of them.\nFor example, the object above is already set to be used either as\nan IUnknown or as an IPersist, since IUnknown is a subset of IPersist.\n<\/p>\n<p>\nOn the other hand, if an object implements multiple interfaces\nthat are not descendants of each other, then you get multiple\ninheritance, in which case the object is typically laid out in\nmemory like this:\n<\/p>\n<table BORDER=\"0\" CELLSPACING=\"0\" CELLPADDING=\"0\" STYLE=\"border-collapse: collapse\">\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 ROWSPAN=\"3\" STYLE=\"border: solid 1px buttonshadow\">&#8230;<br \/>\n          other stuff<br \/>&#8230;<\/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;height: 2em\">Release (2)<\/td>\n<td STYLE=\"border: solid 1px buttonshadow;height: 2em\">&#8230;<\/td>\n<\/tr>\n<tr>\n<td STYLE=\"border: solid 1px buttonshadow;height: 2em\">&#8230;<\/td>\n<\/tr>\n<\/table>\n<p>\nIf you are using an interface that comes from the first vtable, then\nthe interface pointer is p.  But if you&#8217;re using an interface that\ncomes from the second vtable, then the interface pointer is q.\n<\/p>\n<p>\nHang onto that diagram, because\ntomorrow we will learn about those mysterious &#8220;adjustor thunks&#8221;.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>The Win32 COM calling convention specifies the layout of the virtual method table (vtable) of an object. If a language\/compiler wants to support COM, it must lay out its object in the specified manner so other components can use it. It is no coincidence that the Win32 COM object layout matches closely the C++ object [&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-40733","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-history"],"acf":[],"blog_post_summary":"<p>The Win32 COM calling convention specifies the layout of the virtual method table (vtable) of an object. If a language\/compiler wants to support COM, it must lay out its object in the specified manner so other components can use it. It is no coincidence that the Win32 COM object layout matches closely the C++ object [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/40733","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=40733"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/40733\/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=40733"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=40733"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=40733"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}