{"id":110279,"date":"2024-09-18T07:00:00","date_gmt":"2024-09-18T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=110279"},"modified":"2024-09-18T08:51:32","modified_gmt":"2024-09-18T15:51:32","slug":"20240918-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20240918-00\/?p=110279","title":{"rendered":"More on the mysterious <CODE>[default_interface]<\/CODE> attribute in Windows Runtime classes"},"content":{"rendered":"<p>There is this mysterious attribute <code>[default_interface]<\/code> attribute that sometimes gets applied to Windows Runtime classes. What does this attribute mean, and when should you use it?<\/p>\n<p>In the Windows Runtime, the &#8220;default interface&#8221; for a runtime class is the interface that is used at the ABI level to represent the object. <a title=\"Windows Runtime objects are represented by their default interface, so choose your default interface wisely\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20201028-00\/?p=104404\"> We discussed default interfaces some time ago<\/a>, so I&#8217;ll consider that page background reading.<\/p>\n<p>Normally, the default interface for a class is the autogenerated interface that has the same name as the runtime class (with an &#8220;I&#8221; in front). But what if there is no interface to autogenerate?<\/p>\n<pre>runtimeclass WidgetManager\r\n{\r\n    static void DisconnectAllWidgets();\r\n}\r\n<\/pre>\n<p>This class consists only of static members. (In this case, it&#8217;s a static method.) Those static methods go on the activation factory, <!-- backref: The role of the activation factory in the Windows Runtime --> as we discussed earlier.<\/p>\n<p>There are no instance members: No instance properties, no instance methods, no instance events. There is nothing to put in the autogenerated <code>IWidget<\/code> interface.<\/p>\n<p>The MIDL compiler finds this an odd state of affairs. You have an object that you can&#8217;t do anything with. What&#8217;s the point of that? So the compiler says, &#8220;Are you sure?&#8221;<\/p>\n<p>There are two responses to this situation.<\/p>\n<p>&#8220;Oops, sorry. I didn&#8217;t mean for there to be any instances of this class. I should have declared this as a static class.&#8221; In that case, make your class a static class.<\/p>\n<pre><span style=\"border: solid 1px currentcolor;\">static<\/span> runtimeclass WidgetManager\r\n{\r\n    static void DisconnectAllWidgets();\r\n}\r\n<\/pre>\n<p>Another response is &#8220;No really, I want there to be instances of this class. I know it looks funny to have an object that you can&#8217;t do anything with, but trust me, that&#8217;s what I want.&#8221; In that case, you add the <code>[default_interface]<\/code> attribute.<\/p>\n<p>Now, there are cases where the MIDL compiler thinks that you created an object with no methods, but in fact the object does have methods because the methods are implemented by a base class or an implemented interface.<\/p>\n<p>In the case of an interface, you should make that implemented interface be the default interface, so that the default interface is actually useful for something. If you ask for an empty default interface, then the currency for your object is a pointer to an interface that doesn&#8217;t do anything, and any operation people want to perform will have to perform an interface query.<\/p>\n<pre>runtimeclass ExtraHeadersHttpFilter : IHttpFilter\r\n{\r\n    ExtraHeadersHttpFilter(\r\n        IIterable&lt;IKeyValuePair&lt;String, String&gt; &gt; headers);\r\n}\r\n<\/pre>\n<p>The MIDL compiler wonders why you have an <code>Extra\u00adHeaders\u00adHttp\u00adFilter<\/code> that you can&#8217;t do anything with. What it doesn&#8217;t realize is that you <i>can<\/i> do things with it: You can do <code>IHttpFilter<\/code> things.<\/p>\n<p>You can tell the MIDL compiler to shut up by saying, &#8220;Oh, go ahead, make an empty <code>IExtra\u00adHeaders\u00adHttp\u00adFilter<\/code> interface.&#8221;<\/p>\n<pre>\/\/ not the best solution\r\n<span style=\"border: solid 1px currentcolor;\">[default_interface]<\/span>\r\nruntimeclass ExtraHeadersHttpFilter : IHttpFilter\r\n{\r\n    ExtraHeadersHttpFilter(\r\n        IIterable&lt;IKeyValuePair&lt;String, String&gt; &gt; headers);\r\n}\r\n<\/pre>\n<p>This is not the best solution because it means that passing an <code>Extra\u00adHeaders\u00adHttp\u00adFilter<\/code> object as a parameter passes the (empty) <code>IExtra\u00adHeaders\u00adHttp\u00adFilter<\/code> interface, which is not directly usable since it has no members. If somebody wants to call the <code>IHttp\u00adFilter.<wbr \/>Send\u00adRequest\u00adAsync<\/code> method, they will have to perform a <code>Query\u00adInterface<\/code> to convert the <code>IExtra\u00adHeaders\u00adHttp\u00adFilter<\/code> to an <code>IHttp\u00adFilter<\/code>, call the <code>Send\u00adRequest\u00adAsync<\/code> method, and then release the <code>IHttp\u00adFilter<\/code> interface. Much more efficient would be use <code>IHttp\u00adFilter<\/code> as the default interface, so that the recipient can just call <code>IHttp\u00adFilter<\/code> methods immediately.<\/p>\n<p>Therefore, a better fix here is <i>not<\/i> to add <code>[default_interface]<\/code> to say &#8220;That&#8217;s okay, give me an empty default interface.&#8221; Instead, you say that <code>IHttpFilter<\/code> is your default interface.<\/p>\n<pre>runtimeclass ExtraHeadersHttpFilter : <span style=\"border: solid 1px currentcolor;\">[default]<\/span> IHttpFilter\r\n{\r\n    ExtraHeadersHttpFilter(\r\n        IIterable&lt;IKeyValuePair&lt;String, String&gt; &gt; headers);\r\n}\r\n<\/pre>\n<p>Another case where it looks like you have an empty object, but it really does have members is the case where you derive from another class, and the interesting methods are on the base class.<\/p>\n<pre>runtimeclass MyPage : Page\r\n{\r\n    MyPage();\r\n}\r\n<\/pre>\n<p>The Windows Runtime doesn&#8217;t let you name a base class as a default interface, so you are forced to create an empty default interface.<\/p>\n<pre><span style=\"border: solid 1px currentcolor;\">[default_interface]<\/span>\r\nruntimeclass MyPage : Page\r\n{\r\n    MyPage();\r\n}\r\n<\/pre>\n<p><b>Bonus chatter<\/b>: What goes wrong if I say <code>[default_interface]<\/code> when my runtime class does contain instance members? Do I get two interfaces, an empty default interface and a second interface that has the instance members?<\/p>\n<p>No. If the runtime class has instance members, then <code>[default_interface]<\/code> is redundant but not harmful. There was going to be a default interface anyway.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Forcing you to make a choice.<\/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-110279","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Forcing you to make a choice.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/110279","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=110279"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/110279\/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=110279"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=110279"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=110279"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}