{"id":104198,"date":"2020-09-09T07:00:00","date_gmt":"2020-09-09T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=104198"},"modified":"2020-09-09T06:07:22","modified_gmt":"2020-09-09T13:07:22","slug":"20200909-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20200909-00\/?p=104198","title":{"rendered":"The macros for declaring COM interfaces, revisited: C version"},"content":{"rendered":"<p>Quite some time ago, I covered <a title=\"The macros for declaring and implementing COM interfaces\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20041005-00\/?p=37653\"> The macros for declaring and implementing COM interfaces<\/a>. I spelled out the rules, but I didn&#8217;t go into much detail as to how the rules lead to the desired results.<\/p>\n<p>There have also been some changes to the rules in the intervening years, so this mini-series will be a refresh of the old rules.<\/p>\n<pre>#undef  INTERFACE\r\n#define INTERFACE   ISample2\r\n\r\nDECLARE_INTERFACE_IID_(ISample2, ISample,\r\n                       \"5675B786-7BAC-4EA2-A020-F4E7A15E2073\")\r\n{\r\n    BEGIN_INTERFACE\r\n\r\n    \/*** IUnknown methods ***\/\r\n    STDMETHOD(QueryInterface)(THIS_ REFIID riid, void **ppv) PURE;\r\n    STDMETHOD_(ULONG,AddRef)(THIS) PURE;\r\n    STDMETHOD_(ULONG,Release)(THIS) PURE;\r\n\r\n    \/*** ISample methods ***\/\r\n    STDMETHOD(Method1)(THIS) PURE;\r\n    STDMETHOD_(int, Method2)(THIS) PURE;\r\n\r\n    \/*** ISample2 methods ***\/\r\n    STDMETHOD(Method3)(THIS_ int iParameter) PURE;\r\n    STDMETHOD_(int, Method4)(THIS_ int iParameter) PURE;\r\n\r\n    END_INTERFACE\r\n};\r\n<\/pre>\n<p>When this code is compiled by a C compiler, the macros expand as follows:<\/p>\n<pre>\/* DECLARE_INTERFACE_IID_(ISample2, ISample, \"...\") *\/\r\ntypedef struct ISample2\r\n{\r\n    struct ISample2Vtbl* lpVtbl;\r\n} ISample2;\r\n\r\ntypedef struct ISample2Vtbl ISample2Vtbl;\r\n\r\nstruct ISample2Vtbl\r\n{\r\n    \/* BEGIN_INTERFACE *\/\r\n    void* b; \/* only on PowerPC *\/\r\n\r\n    \/*** IUnknown methods ***\/\r\n    \/* STDMETHOD(QueryInterface)(THIS_ REFIID riid, void **ppv) PURE; *\/\r\n    HRESULT (__stdcall* QueryInterface)(ISample2* This, REFIID riid, void** ppv);\r\n\r\n    \/* STDMETHOD_(ULONG,AddRef)(THIS) PURE; *\/\r\n    ULONG (__stdcall* AddRef)(ISample2* This);\r\n\r\n    \/* STDMETHOD_(ULONG,Release)(THIS) PURE; *\/\r\n    ULONG (__stdcall* Release)(ISample2* This);\r\n\r\n    \/*** ISample methods ***\/\r\n    \/* STDMETHOD(Method1)(THIS) PURE; *\/\r\n    HRESULT (__stdcall* Method1)(ISample2* This);\r\n\r\n    \/* STDMETHOD_(int, Method2)(THIS) PURE; *\/\r\n    int (__stdcall* Method2(ISample2* This);\r\n\r\n    \/*** ISample2 methods ***\/\r\n    \/* STDMETHOD(Method3)(THIS_ int iParameter) PURE; *\/\r\n    HRESULT (__stdcall* Method3)(int iParameter);\r\n\r\n    \/* STDMETHOD_(int, Method4)(THIS_ int iParameter) PURE; *\/\r\n    int (__stdcall* Method4)(int iParameter);\r\n\r\n    \/* END_INTERFACE *\/\r\n};\r\n<\/pre>\n<p>When compiled as C, the interface is formally defined as a structure consisting only of a vtable. The vtable is a sequence of function pointers, one for each virtual method.<\/p>\n<p>The parameters to the <code>DECLARE_<\/code><code>INTERFACE_<\/code><code>IID_<\/code> macro are the interface being declared, its base interface, and the UUID for the interface. There&#8217;s also a version without the trailing underscore: <code>DECLARE_<\/code><code>INTERFACE_<\/code><code>IID<\/code>. That version is for the case where there is no base interface. In practice, you will never use that version because every interface derives from <code>IUnknown<\/code>. Basically, the only interface that would use the no-base-interface version is <code>IUnknown<\/code> itself.<\/p>\n<p>There&#8217;s also a no-IID version of the macro: <code>DECLARE_<\/code><code>INTERFACE_<\/code> (and <code>DECLARE_<\/code><code>INTERFACE<\/code> for the one interface with no base interface). If you use this version, then you won&#8217;t be able to say <code>__uuidof(ISample2)<\/code> in the C++ expansion to obtain the IID of the interface. We&#8217;ll see more about this when we dig into the C++ expansion.<\/p>\n<p>The <code>BEGIN_<\/code><code>INTERFACE<\/code> macro does nothing on most systems, but on PowerPC, it generates a mysterious <code>void*<\/code> at the start of the vtable. I don&#8217;t know why it&#8217;s there, but apparently that was part of the PowerPC ABI for vtables. A common mistake is forgetting the <code>BEGIN_<\/code><code>INTERFACE<\/code> and <code>END_<\/code><code>INTERFACE<\/code> macros. You don&#8217;t notice until somebody tries to use your header file on a PowerPC.<\/p>\n<p>Notice that all the methods of the base classes need to be redeclared in the derived class, so that the vtable is laid out properly. A common mistake is to omit the base interface methods, and you get away with it when compiling as C++ because the base interface methods are inherited. But C doesn&#8217;t have inheritance. You have to write it out.<\/p>\n<p>The <code>STDMETHOD<\/code> and <code>STDMETHOD_<\/code> macros generate a function pointer structure member, corresponding to a C++ virtual method, using the calling convention for COM methods, which happens to be <code>__stdcall<\/code>. The <code>STDMETHOD<\/code> macro is for methods returning <code>HRESULT<\/code>, and the <code>STDMETHOD_<\/code> macro is for methods that return something else.<\/p>\n<p>The <code>PURE<\/code> macro expands to nothing. It&#8217;s used by the C++ expansion, which we&#8217;ll cover later.<\/p>\n<p>The <code>THIS<\/code> and <code>THIS_<\/code> macros expand to the <code>This<\/code> parameter declaration, corresponding to the hidden <code>this<\/code> parameter in C++. For methods with no parameters, use <code>THIS<\/code> as the single parameter. For methods that have parameters, use <code>THIS_<\/code> before the first parameter.<\/p>\n<p>The <code>END_<\/code><code>INTERFACE<\/code> macro expands to nothing. There hasn&#8217;t yet been an architecture that required special treatment of the end of the vtable. But the macro is there in case some future architecture ends up needing something to go there.<\/p>\n<p>Next time, we&#8217;ll look at how these macros expand in C++.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Following the expansion.<\/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-104198","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Following the expansion.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/104198","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=104198"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/104198\/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=104198"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=104198"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=104198"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}