{"id":28783,"date":"2006-12-08T10:00:00","date_gmt":"2006-12-08T10:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2006\/12\/08\/do-not-overload-the-e_nointerface-error\/"},"modified":"2006-12-08T10:00:00","modified_gmt":"2006-12-08T10:00:00","slug":"do-not-overload-the-e_nointerface-error","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20061208-00\/?p=28783","title":{"rendered":"Do not overload the E_NOINTERFACE error"},"content":{"rendered":"<p>One of the more subtle ways <a href=\"http:\/\/blogs.msdn.com\/oldnewthing\/archive\/2004\/03\/26\/96777.aspx\"> people mess up <code>IUnknown::QueryInterface<\/code><\/a> is returning <code>E_NOINTERFACE<\/code> when the problem wasn&#8217;t actually an unsupported interface. The <code>E_NOINTERFACE<\/code> return value has very specific meaning. Do not use it as your generic &#8220;gosh, something went wrong&#8221; error. (Use an appropriate error such as <code>E_OUTOFMEMORY<\/code> or <code>E_ACCESSDENIED<\/code>.)\n Recall that the rules for <code>IUnknown::QueryInterface<\/code> are that (in the absence of catastrophic errors such as <code>E_OUTOFMEMORY<\/code>) if a request for a particular interface succeeds, then it must always succeed in the future for that object. Similarly, if a request fails with <code>E_NOINTERFACE<\/code>, then it must always fail in the future for that object.\n These rules exist for a reason.\n In the case where COM needs to create a proxy for your object (for example, to marshal the object into a different apartment), the COM infrastructure does a lot of interface caching (and negative caching) for performance reasons. For example, if a request for an interface fails, COM remembers this so that future requests for that interface are failed immediately rather than being marshalled to the original object only to have the request fail anyway. Requests for unsupported interfaces are very common in COM, and optimizing that case yields significant performance improvements.\n If you start returning <code>E_NOINTERFACE<\/code> for problems other than &#8220;The object doesn&#8217;t support this interface&#8221;, COM will assume that the object really doesn&#8217;t support the interface and may not ask for it again even if you do. This in turn leads to very strange bugs that defy debugging: You are at a call to <code>IUnknown::QueryInterface<\/code>, you set a breakpoint on your object&#8217;s implementation of <code>IUnknown::QueryInterface<\/code> to see what the problem is, you step over the call and get <code>E_NOINTERFACE<\/code> back without your breakpoint ever hitting. Why? Because at some point in the past, you said you didn&#8217;t support the interface, and COM remembered this and &#8220;saved you the trouble&#8221; of having to respond to a question you already answered. The COM folks tell me that they and their comrades in product support end up spending hours debugging customer&#8217;s problems like &#8220;When my computer is under load, sometimes I start getting <code>E_NOINTERFACE<\/code> for interfaces I definitely support.&#8221;<\/p>\n<p> Save yourself and the COM folks several hours of frustration. Don&#8217;t return <code>E_NOINTERFACE<\/code> unless you really mean it. <\/p>\n","protected":false},"excerpt":{"rendered":"<p>One of the more subtle ways people mess up IUnknown::QueryInterface is returning E_NOINTERFACE when the problem wasn&#8217;t actually an unsupported interface. The E_NOINTERFACE return value has very specific meaning. Do not use it as your generic &#8220;gosh, something went wrong&#8221; error. (Use an appropriate error such as E_OUTOFMEMORY or E_ACCESSDENIED.) Recall that the rules for [&hellip;]<\/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-28783","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>One of the more subtle ways people mess up IUnknown::QueryInterface is returning E_NOINTERFACE when the problem wasn&#8217;t actually an unsupported interface. The E_NOINTERFACE return value has very specific meaning. Do not use it as your generic &#8220;gosh, something went wrong&#8221; error. (Use an appropriate error such as E_OUTOFMEMORY or E_ACCESSDENIED.) Recall that the rules for [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/28783","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=28783"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/28783\/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=28783"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=28783"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=28783"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}