{"id":104404,"date":"2020-10-28T07:00:00","date_gmt":"2020-10-28T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=104404"},"modified":"2023-01-03T09:01:49","modified_gmt":"2023-01-03T17:01:49","slug":"20201028-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20201028-00\/?p=104404","title":{"rendered":"Windows Runtime objects are represented by their default interface, so choose your default interface wisely"},"content":{"rendered":"<p>As I noted some time ago, in the Windows Runtime, <a href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20200324-00\/?p=103586\"> objects are represented at the ABI by a pointer to their default interface<\/a>. The choice of default interface is usually obvious, but on occasion, the non-obvious choice may be better.<\/p>\n<p>If your runtime object supports only one interface, then you have no choice but to make that interface the default interface. But if your runtime object supports multiple interfaces, then you have a choice. For example:<\/p>\n<pre>runtimeclass AudioTrack : IMediaTrack\r\n{\r\n    event Windows.Foundation.TypedEventHandler&lt;AudioTrack, AudioTrackOpenedEventArgs&gt;\r\n        OpenFailed;\r\n\r\n    AudioEncodingProperties GetEncodingProperties();\r\n    MediaPlaybackItem PlaybackItem { get; };\r\n    String Name { get; };\r\n    AudioTrackSupportInfo SupportInfo { get; };\r\n};\r\n<\/pre>\n<p>As written, the MIDL compiler does the following:<\/p>\n<ul>\n<li>Autogenerates an interface called <code>IAudioTrack<\/code> to contain the members declared in the class definition.<\/li>\n<li>Defines the <code>AudioTrack<\/code> class as implementing the <code>IAudioTrack<\/code> and <code>IMediaTrack<\/code> interfaces.<\/li>\n<li>Marks the <code>IAudioTrack<\/code> class as the default interface.<\/li>\n<\/ul>\n<p>As noted above, the default interface is used to represent the object. Method calls on the default interface will be faster than method calls on non-default interfaces, because <a href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20200324-00\/?p=103586\"> methods on non-default interfaces require a <code>Query\u00adInterface<\/code> to obtain the interface<\/a>. Therefore, you should choose your default interface to be one that holds the methods that you anticipate will be used the most. If that interface is not the autogenerated interface, you can specify a custom default interface by putting the word <code>[default]<\/code> in front of the interface you want to be the default interface:<\/p>\n<pre>runtimeclass AudioTrack : <span style=\"color: #08f;\">[default]<\/span> IMediaTrack\r\n{\r\n    event Windows.Foundation.TypedEventHandler&lt;AudioTrack, AudioTrackOpenedEventArgs&gt;\r\n        OpenFailed;\r\n\r\n    AudioEncodingProperties GetEncodingProperties();\r\n    MediaPlaybackItem PlaybackItem { get; };\r\n    String Name { get; };\r\n    AudioTrackSupportInfo SupportInfo { get; };\r\n};\r\n<\/pre>\n<p>In this case, the object will be used primarily as a media track, and it is the methods on <code>IMediaTrack<\/code> that will get the most exercise. Registering for the <code>OpenFailed<\/code> event will probably happen only once, and the support info might never be used at all. It would be preferable to make the <code>IMediaTrack<\/code> the default interface, so that the commonly-used methods are readily available.<\/p>\n<p>Another scenario where you may want to override the MIDL compiler&#8217;s choice of default interface is if your class implements a collection, possibly with an extra method or two. The object will almost certainly be used as a collection, so you should choose the collection as your default interface:<\/p>\n<pre>runtimeclass PlayerCollection : [default] <a href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20200316-00\/?p=103564\">IVector<\/a>&lt;Page&gt;,\r\n{\r\n  void MoveToIndex(Player player, Int32 newIndex);\r\n}\r\n<\/pre>\n<p>This hypothetical <code>Player\u00adCollection<\/code> class implements <code>IVector<\/code>, so you can do all the normal vector things with it. But <code>IVector<\/code> doesn&#8217;t support reordering items. That&#8217;s why the <code>Play\u00adCollection<\/code> has a bonus <code>Move\u00adTo\u00adIndex<\/code> method that lets you take an item in the collection and move it to another position. The class may offer this so that it can provide a more suitable animation: You could get the same effect by removing the player and then reinserting it at the desired new index. However, that would result in a delete animation followed by an insertion animation, rather than a reordering animation.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>The choice is usually obvious, but on occasion, the non-obvious choice may be better.<\/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-104404","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>The choice is usually obvious, but on occasion, the non-obvious choice may be better.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/104404","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=104404"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/104404\/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=104404"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=104404"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=104404"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}