{"id":104203,"date":"2020-09-10T07:00:00","date_gmt":"2020-09-10T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=104203"},"modified":"2020-09-10T07:10:47","modified_gmt":"2020-09-10T14:10:47","slug":"20200910-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20200910-00\/?p=104203","title":{"rendered":"The macros for declaring COM interfaces, revisited: C++ version"},"content":{"rendered":"<p>Last time, we looked at <a title=\"The macros for declaring COM interfaces, revisited: C version\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20200909-00\/?p=104198\"> the macros for declaring COM interfaces and how they expand when compiled for C<\/a>.<\/p>\n<p>When compiled as C++, the macros do something entirely different.<\/p>\n<pre>\/* DECLARE_INTERFACE_IID_(ISample2, ISample, \"...\") *\/\r\nstruct __declspec(uuid(\"5675B786-7BAC-4EA2-A020-F4E7A15E2073\"))\r\n       __declspec(novtable)\r\n       ISample2 : public ISample\r\n{\r\n    \/* BEGIN_INTERFACE *\/\r\n    virtual void a() {} \/\/ only on PowerPC\r\n\r\n    \/\/ *** IUnknown methods ***\r\n    \/* STDMETHOD(QueryInterface)(THIS_ REFIID riid, void **ppv) PURE; *\/\r\n    virtual __declspec(nothrow) HRESULT __stdcall\r\n        QueryInterface(REFIID riid, void** ppv) = 0;\r\n\r\n    \/* STDMETHOD_(ULONG,AddRef)(THIS) PURE; *\/\r\n    virtual __declspec(nothrow) ULONG __stdcall AddRef(void) = 0;\r\n\r\n    \/* STDMETHOD_(ULONG,Release)(THIS) PURE; *\/\r\n    virtual __declspec(nothrow) ULONG __stdcall Release(void) = 0;\r\n\r\n    \/\/ ** ISample methods ***\r\n    \/* STDMETHOD(Method1)(THIS) PURE; *\/\r\n    virtual __declspec(nothrow) HRESULT __stdcall Method1(void) = 0;\r\n\r\n    \/* STDMETHOD_(int, Method2)(THIS) PURE; *\/\r\n    virtual __declspec(nothrow) HRESULT __stdcall Method2(void) = 0;\r\n\r\n    \/\/ *** ISample2 methods ***\r\n    \/* STDMETHOD(Method3)(THIS_ int iParameter) PURE; *\/\r\n    virtual __declspec(nothrow) HRESULT __stdcall Method3(int iParameter) = 0;\r\n\r\n    \/* STDMETHOD_(int, Method4)(THIS_ int iParameter) PURE; *\/\r\n    virtual __declspec(nothrow) int __stdcall Method4(int iParameter) = 0;\r\n\r\n    \/* END_INTERFACE *\/\r\n};\r\n<\/pre>\n<p>The <code>DECLARE_<\/code><code>INTERFACE<\/code> macros declare a structure that consists solely of pure virtual methods. If you use the <code>DECLARE_<\/code><code>INTERFACE_<\/code> version, you can specify a base interface. You will pretty much always use this two-parameter version, since you need to derive from <code>IUnknown<\/code> if nothing else.<\/p>\n<p>The <code>__declspec(uuid(...))<\/code> specifier enables the use of <code>__uuidof<\/code> to auto-generate a GUID when you write <code>__uuidof(ISample2)<\/code>. This is very handy for macros like <code>IID_PPV_ARGS<\/code> which automatically pass the interface GUID that corresponds to the macro parameter, thereby avoiding errors due to mismatches.<\/p>\n<p>Normally, C++ objects change identity during construction and destruction, which means that constructing the interface object involves setting up a vtable filled with <a title=\"What is __purecall?\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20040428-00\/?p=39613\"> <code>__purecall<\/code><\/a> entries, only to have that vtable be immediately overwritten when the derived class is constructed. Similarly, at destruction, the vtable regresses from the derived class&#8217;s vtable to the <code>__purecall<\/code> vtable when destruction reaches the interface object.<\/p>\n<p>The <code>__declspec(novtable)<\/code> specifier tells the compiler not to bother setting up the vtable for this class during construction and destruction, because the class promises not to call any of its own virtual methods during constructor or destruction. (Vacuously true for interfaces because they have trivial constructors and destructors.) The <code>novtable<\/code> specifier avoids the code needed to set up the vtables as well as not needing to produce a vtable in the first place.<\/p>\n<p><b>Related<\/b>: <a title=\"The sad history of Visual Studio's custom __if_exists keyword\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20190828-00\/?p=102812\"> The sad history of Visual Studio&#8217;s custom <code>__if_exists<\/code> keyword<\/a>.<\/p>\n<p>As we learned last time, the <code>BEGIN_<\/code><code>INTERFACE<\/code> macro usually does nothing, but on PowerPC, it generates an extra dummy entry in the vtable for reasons lost to history.<\/p>\n<p>The <code>STDMETHOD<\/code> macro generates the method declaration. The method is <code>virtual<\/code>, as you would expect. It also is marked <code>__declspec(nothrow)<\/code>, which is a promise that calling the method will not throw an exception. There is no enforcement of this promise; if you break the rules and allow an exception to escape, then the behavior is undefined. COM methods are not allowed to throw exceptions, so this annotation is accurate, assuming everybody plays by the rules.<\/p>\n<p><b>Related<\/b>: <a title=\"The sad history of the C++ throw(\u2026) exception specifier\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20180928-00\/?p=99855\"> The sad history of the C++ <code>throw(\u2026)<\/code> exception specifier<\/a>.<\/p>\n<p>The <code>PURE<\/code> expands to <code>= 0<\/code> for C++, which makes it a pure virtual method.<\/p>\n<p><b>Related<\/b>: COM interfaces do not implement their own pure virtual methods, even though <a title=\"C++ corner case: You can implement pure virtual functions in the base class\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20131011-00\/?p=2953\"> the language permits it<\/a>.<\/p>\n<p>The rest is fairly straightforward. The <code>THIS<\/code> and <code>THIS_<\/code> macros expand to nothing; they exist to keep C happy.<\/p>\n<p>Every macro in this entire sequence does something, either in C or C++. Well, with the exception of <code>END_<\/code><code>INTERFACE<\/code>, which nobody has yet to find a use for. But it&#8217;s there just in case.\u00b9<\/p>\n<p>Next time, we&#8217;ll look at the implementation macros.<\/p>\n<p>\u00b9 For example, it might be used to declare an explicitly nonvirtual destructor, should the C++ language someday decide to make destructors virtual by default in polymorphic classes.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Apparently there&#8217;s this new language people are using nowadays.<\/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-104203","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Apparently there&#8217;s this new language people are using nowadays.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/104203","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=104203"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/104203\/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=104203"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=104203"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=104203"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}