{"id":103586,"date":"2020-03-24T07:00:00","date_gmt":"2020-03-24T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=103586"},"modified":"2020-03-24T05:52:48","modified_gmt":"2020-03-24T12:52:48","slug":"20200324-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20200324-00\/?p=103586","title":{"rendered":"Accessing a member of a Windows Runtime class raises an <CODE>Invalid&shy;Cast&shy;Exception<\/CODE> \/ throws a <CODE>hresult_<\/CODE><CODE>no_<\/CODE><CODE>interface<\/CODE>, what does this mean?"},"content":{"rendered":"<p>You&#8217;re minding your own business and you decide to call a method on some object. Everything compiles fine, but it crashes at runtime with <code>Invalid\u00adCast\u00adException<\/code>:<\/p>\n<pre>\/\/ C#\r\nvar options = new LauncherOptions();\r\noptions.IgnoreAppUriHandlers = true; \/\/ System.InvalidCastException\r\n\r\n\/\/ C++\/WinRT\r\nLauncherOptions options;\r\noptions.IgnoreAppUriHandlers(true); \/\/ winrt::hresult_no_interface \r\n\r\n\/\/ C++\/CX\r\nauto options = ref new LauncherOptions();\r\noptions-&gt;IgnoreAppUriHandlers = true; \/\/ Platform::InvalidCastException\r\n<\/pre>\n<p>Why am I getting an &#8220;invalid cast exception&#8221; when there is no casting going on at all?<\/p>\n<p>The clue is in the C++\/WinRT example, which throws <code>winrt::<\/code><code>hresult_<\/code><code>no_<\/code><code>interface<\/code>.<\/p>\n<p>Under the covers, Windows Runtime objects are COM objects, and their members are methods on COM interfaces. When you use a member, what happens behind the scenes is that the language projection queries the object for the COM interface that implements the desired member, and then it calls the corresponding interface method.<\/p>\n<p>One of the rules of COM is that interfaces are immutable. Therefore, in order to add new members to the object, those new members need to be put on a new interface.<\/p>\n<p>For example, the members of the <code>Launcher\u00adOptions<\/code> runtime class were introduced as follows:<\/p>\n<table style=\"border-collapse: collapse;\" border=\"1\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<td>Windows 8<br \/>\n<tt>ILauncher\u00adOptions<\/tt><\/td>\n<td><tt>Treat\u00adAs\u00adUntrusted<tt><br \/>\n<tt>Display\u00adApplication\u00adPicker<tt><br \/>\n<tt>UI<tt><br \/>\n<tt>Preferred\u00adApplication\u00adPackage\u00adFamily\u00adName<tt><br \/>\n<tt>Preferred\u00adApplication\u00adDisplay\u00adName<tt><br \/>\n<tt>Fallback\u00adUri<tt><br \/>\n<tt>Content\u00adType<tt><\/tt><\/tt><\/tt><\/tt><\/tt><\/tt><\/tt><\/tt><\/tt><\/tt><\/tt><\/tt><\/tt><\/tt><\/td>\n<\/tr>\n<tr>\n<td>Windows 10 version 1507<br \/>\n<tt>ILauncher\u00adOptions2<tt><\/tt><\/tt><\/td>\n<td><tt>Target\u00adApplication\u00adPackage\u00adFamily\u00adName<tt><br \/>\n<tt>Neighboring\u00adFiles\u00adQuery<tt><\/tt><\/tt><\/tt><\/tt><\/td>\n<\/tr>\n<tr>\n<td>Windows 10 version 1607<br \/>\n<tt>ILauncher\u00adOptions3<tt><\/tt><\/tt><\/td>\n<td><tt>Ignore\u00adApp\u00adUri\u00adHandlers<tt><\/tt><\/tt><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Internally, a Windows Runtime object is represented by its &#8220;default interface&#8221;. Deciding upon a default interface is usually a no-brainer, because a freshly-introduced object typically implements only one interface anyway.\u00b9 For example, in Windows 8, the only interface supported by <code>Launcher\u00adOptions<\/code> is <code>ILauncher\u00adOptions<\/code>, which makes <code>ILauncher\u00adOptions<\/code> the default interface, seeing as you have no choice.<\/p>\n<p>Using one of the Windows 8 properties goes like this:<\/p>\n<pre>\/\/ C#:        options.TreatAsUntrusted = true;\r\n\/\/ C++\/CX:    options-&gt;TreatAsUntrusted = true;\r\n\/\/ C++\/WinRT: options.TreatAsUntrusted(true);\r\n\r\n\/\/ options is already a ILauncherOptions.\r\noptions-&gt;put_TreatAsUntrusted(true);\r\n<\/pre>\n<p>But using one of the properties added later takes a little more work:<\/p>\n<pre>\/\/ C#:        options.IgnoreAppUriHandlers = true;\r\n\/\/ C++\/CX:    options-&gt;IgnoreAppUriHandlers = true;\r\n\/\/ C++\/WinRT: options.IgnoreAppUriHandlers(true);\r\n\r\nILauncherOptions3* options3;\r\noptions-&gt;QueryInterface(IID_PPV_ARGS(&amp;options3));\r\noptions3-&gt;put_IgnoreAppUriHandlers(true);\r\noptions3-&gt;Release();\r\n<\/pre>\n<p>If you take a program that uses <code>Ignore\u00adApp\u00adUri\u00adHandlers<\/code> and run it on on a version of Windows that doesn&#8217;t support the property, the <code>Query\u00adInterface<\/code> call fails with <code>E_<\/code><code>NO\u00adINTERFACE<\/code>. The language projection then converts this into a language-specific exception.<\/p>\n<ul>\n<li>C# <a href=\"https:\/\/docs.microsoft.com\/en-us\/dotnet\/api\/system.invalidcastexception?view=netframework-4.8\"> converts it to a <code>System.<\/code><code>Invalid\u00adCast\u00adException<\/code><\/a>.<\/li>\n<li>C++\/CX <a href=\"https:\/\/docs.microsoft.com\/en-us\/cpp\/cppcx\/platform-comexception-class?view=vs-2019\"> converts it to a <code>Platform.<\/code><code>Invalid\u00adCast\u00adException<\/code><\/a>.<\/li>\n<li>C++\/WinRT <a href=\"https:\/\/github.com\/microsoft\/cppwinrt\/blob\/61b62611484dc7dede489ee4d7dcc4306e924cc7\/strings\/base_error.h#L326\"> converts it to a <code>winrt.<\/code><code>hresult_<\/code><code>no_<\/code><code>interface<\/code><\/a>.<\/li>\n<\/ul>\n<p>C# and C++\/CX report this as an <code>Invalid\u00adCast\u00adException<\/code>, because the common case for this is where you try to cast an object to an interface that it doesn&#8217;t support.<\/p>\n<p>Instead of adding new interfaces, you might be tempted to add new members to the existing interface, in violation of COM rules. But that would result in profound sadness if a program tried to use one of those new members when running on a system that doesn&#8217;t support it:<\/p>\n<pre>\/\/ C#:        options.IgnoreAppUriHandlers = true;\r\n\/\/ C++\/CX:    options-&gt;IgnoreAppUriHandlers = true;\r\n\/\/ C++\/WinRT: options.IgnoreAppUriHandlers(true);\r\n\/\/\r\n\/\/ In hypothetical world where new members\r\n\/\/ are added to ILauncherOptions.\r\n\r\noptions-&gt;put_IgnoreAppUriHandlers(true);\r\n<\/pre>\n<p>Since there is no <code>put_<\/code><code>Ignore\u00adApp\u00adUri\u00adHandlers<\/code> method in the vtable on older versions of Windows, this results not only in reading past the end of the vtable, but taking the undefined value past the end of the vtable and treating it as a function pointer! If you&#8217;re lucky, this crashes unrecoverably. If you&#8217;re unlucky, this is a security vulnerability.<\/p>\n<p>Now that we understand the source of the invalid cast exception, we can look next time at what we can do about it.<\/p>\n<p>\u00b9 The default interface may not be <code>IUnknown<\/code> or <code>IInspectable<\/code>.<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>It&#8217;s interfaces under the hood.<\/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-103586","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>It&#8217;s interfaces under the hood.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/103586","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=103586"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/103586\/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=103586"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=103586"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=103586"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}