Do not overload the E_NOINTERFACE error

Date:December 8, 2006 / year-entry #407
Tags:code
Orig Link:https://blogs.msdn.microsoft.com/oldnewthing/20061208-00/?p=28783
Comments:    26
Summary:One of the more subtle ways people mess up IUnknown::QueryInterface is returning E_NOINTERFACE when the problem wasn't actually an unsupported interface. The E_NOINTERFACE return value has very specific meaning. Do not use it as your generic "gosh, something went wrong" error. (Use an appropriate error such as E_OUTOFMEMORY or E_ACCESSDENIED.) Recall that the rules for...

One of the more subtle ways people mess up IUnknown::QueryInterface is returning E_NOINTERFACE when the problem wasn't actually an unsupported interface. The E_NOINTERFACE return value has very specific meaning. Do not use it as your generic "gosh, something went wrong" error. (Use an appropriate error such as E_OUTOFMEMORY or E_ACCESSDENIED.)

Recall that the rules for IUnknown::QueryInterface are that (in the absence of catastrophic errors such as E_OUTOFMEMORY) 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 E_NOINTERFACE, then it must always fail in the future for that object.

These rules exist for a reason.

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.

If you start returning E_NOINTERFACE for problems other than "The object doesn't support this interface", COM will assume that the object really doesn'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 IUnknown::QueryInterface, you set a breakpoint on your object's implementation of IUnknown::QueryInterface to see what the problem is, you step over the call and get E_NOINTERFACE back without your breakpoint ever hitting. Why? Because at some point in the past, you said you didn't support the interface, and COM remembered this and "saved you the trouble" 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's problems like "When my computer is under load, sometimes I start getting E_NOINTERFACE for interfaces I definitely support."

Save yourself and the COM folks several hours of frustration. Don't return E_NOINTERFACE unless you really mean it.


Comments (26)
  1. Lorenzo says:

    There’s a way to clean the cache? In a developement environment it
    would be possible that at some early stage of a project QueryInterface
    would retutn E_NOINTERFACE because the requested interface is not yet
    supported.

  2. Carlos says:

    Lorenzo: the cache is per-object (not class), so it is necessarily not persistent.  i.e. If you restart you application you’ll get a clean cache.

  3. Spikey says:

    Is this behavior documented?

    [It’s documented in every single book on COM that I’ve seen – in fact books tend to harp on this point, not gloss over it – as well as in MSDN under the impossible-to-guess title Rules for implementing QueryInterface. -Raymond]
  4. JamesNT says:

    Mr. Chen,

    On a recent post, you determined that you should become a professional psychic since your predictions seem to have a reasonably high favorable probability.  Perhaps we should turn your powers to something very useful such as answering the following:

    1.  How many of those who post in my comments section are slashdotters who just want to pick a fight as opposed to those who wish to learn?
    2.  How many of those in my comments section who claim to be professional developers have actually seen at least one day of formal training?

    3.  How many of those in my comments section really do read the API documentation and perform adequate research as opposed to "programming from the hip?"

    4.  Why do so many of those in my comments section not believe in things such as backward compatibility and good interface design?

    5.  And last, but not least:  Why is it that no matter how hard I work my life out to ensure back compat, security, and stability in every line of code I write for Windows, Microsoft is seen as inherently evil while linux can break almost every driver written for it when upgrading from kernal version 2.4 to 2.6 and it is seen as a godsend?

    James

  5. Mikkin says:

    James – you forgot one:

    6.  Why not delete random off-topic rants?

    [People get flamed for deleting comments (for reasons other than spam). I get flamed for enough stuff, adding “censorship” to the list doesn’t help. -Raymond]
  6. HIC says:

    > Use an appropriate error such as E_OUTOFMEMORY or E_ACCESSDENIED

    we shouldn’t return E_NOTIMPL??

    [I’m going to assume that was a joke. -Raymond]
  7. Bob (still no relation) says:

    Or here’s a question: Why must every thread this month involve sycophantic praise of Microsoft and knee-jerk retaliatory bashing of Linux and /.? Seriously, man, pretty much every post you make follows the same formula.

    More on topic, it seems from reading the linked COM article that rule 1 for supporting extensions, whether you’re writing a shell or just a Winamp plugin, seems to be that version 1.0 must enforce every conceivable restriction, including the ones that don’t seem to make any sense. If this proves to be sluggish in practice, just do it for any plugin timestamped within the last two months.

  8. JamesNT says:

    Bob,

    I’m going to assume you were speaking to me so apologies up front if I’m wrong.  As to your question, here is my answer:

    Because for the past several YEARS every other article on slashdot involved abhorrent hatred of Microsoft and knee-jerk retaliatory bashing of Windows.

    I find it strange how it’s cool to go in one direction and not cool to go in the other.

    James

  9. Cooney (Bob's yer uncle) says:

    What, even the articles about solar panels? Perhaps some people are smarting from Linux being regarded as a toy even when it does what people need better than certain other OSes. It’s also irritating that people assume the only reason that MS stuff is so regularly rooted is popularity and nothing to do with design or priorities.

  10. Centaur says:

    Did something change just recently that would make such bugs more visible? This seems *psychically* close to something I am experiencing.

    An application that I depend on registers a COM object in ROT. I retrieve a proxy to it and ask for a couple of interfaces. It gives me both under Windows XP, but only one under Vista. With E_NOINTERFACE on the other interface.

  11. Igor says:

    Random Linux User: Windows is trash

    Me: Still 94.16% of people use Windows

    Random Linux User: Linux is better for everything

    Me: Seriously, who gives a damn?

    Take a look at this:

    http://marketshare.hitslink.com/report.aspx?qprid=2&qptimeframe=M&qpsp=94

    Note how even MacOS has several times higher market share than Linux even though it is not free.

    So please stop the flame war right now because this really isn’t the place to pile up junk off-topic comments.

  12. Stu says:

    Igor: Market share numbers prove nothing. Is a Ford better than a Ferrari?

  13. Cheong says:

    Yep. Or a more appropiate one: Are automatic Digital Cameras better than manual traditional ones?

    Average people can use DCs and take good photos in a short time, but you really need "to know something" before using a traditional one, of which every settings like focus or so must be tuned by yourself.

    Having fewer people using traditional camera doesn’t prove one is inferior than the others or vice versa.

  14. Reuven says:

    Reminds me of a problem we had to solve once.  We needed a way of checking whether a COM server was still alive.  The interface was already fixed, so an isAlive function wasn’t an option.  My first attempt called QueryIterface(uuidof(IUnknown)) periodically, since that must succeed.  Due to caching though, it continues to succeed when the server crashes.  I finally ended up periodically querying for randomly-created GUIDs.  E_NOINTERFACE meant the server was up, some other error meant the server was presumably down.  Creating a new GUID each time kept the caching at bay.

  15. Aleksander Oven says:

    I was wondering about this a quote from the ‘Rules for implementing QueryInterface’ page to which Raymond linked:

    "For any given object instance, a call to QueryInterface(IID_IUnknown, …) must always return the same physical pointer value. This allows you to call QueryInterface(IID_IUnknown, …) on any two interfaces and compare the results to determine whether they point to the same instance of an object."

    How exactly does one compare the two pointers and deduct whether they point to the same object or not?

    I they point to two distinct entries in the interface table they are different, aren’t they?

  16. Dean Harding says:

    Aleksander: That’s why you have to query for IUnknown. If you have a point to IInterface1 and another pointer to IInterface2, then even if its the same physical object, the pointers will necessarily be different. The IUnknown rule is there so that you can do a QueryInterface on each of IInterface1 and IInterface2, test the results of those and if THEY’RE equal, it’s the same object.

    And to the people arguing over whether Linux or Windows is better, who cares? I’m in the business of selling software, so I’m going to concentrate my efforts on the platform that will result in the largest returns for my effort. If I had time to spare for Linux (or even Mac OS), I would, but my time is better spent where 95% of my potential customers are…

  17. Igor says:

    Stu said:

    "Market share numbers prove nothing."

    Those are the numbers for desktop OS market share and they prove the following:

    1. People use Windows despite Random Linux Users screaming how Windows is the utmost crap
    2. A lot of them do so (like more than 90%)

    You can conclude that either:

    a) more than 90% of people are really stupid

    b) less than 0.5% of people is really smart

    c) Windows is not as bad when it comes to desktop use

    d) Linux is not as good when it comes to desktop use

    Circle all that apply. I personally vote for c) and d).

    a) and b) choices are reserved for those who use the same type of reality distortion field as Mac users.

    Stu said:

    "Is a Ford better than a Ferrari?"

    Cheong said:

    "Are automatic Digital Cameras better than manual traditional ones?"

    Yes and yes. They both have much better price/performance ratio for the majority of users.

  18. Sven Groot says:

    If there’s one thing that annoys me, it’s COM objects that return E_FAIL for absolutely everything.

    Even worse are apps that display them to the user.

    Friend: Help, app X doesn’t work!

    Me: What error are you getting?

    App X: "Total everything failure: 0x80040005"

    Me: That’s soooo not helpful.

    Worst are apps that manage to display it in decimal instead of hex.

    If anybody who reads this blog every has to implement a COM object: please, just take those extra thirty minutes and implement IErrorInfo.

  19. Stu says:

    Igor:

    Or, Microsoft’s marketing machine is so good compared to the various Linux distributors that 90% of users do not realize there is an alternative, or believe that Windows is “good enough” (in many cases, it probably is, but in many of those, Linux would also be “good enough”, there just isn’t any great reason to switch).

    Thus we can explain the “popularity” of Windows, without mentioning its quality or the intelligence of its users.

    [What does this have to do with QueryInterface? -Raymond]
  20. Stu says:

    [What does this have to do with QueryInterface? -Raymond]

    Nothing, sorry, went a bit off-topic there…

  21. JamesNT says:

    Yeah, going off topic is also my fault.  I apologize, Mr. Chen.

    James

  22. Neil says:

    I believe you can even have two IInterface2 pointers pointing to
    different physical (C++) objects but representing the same logical
    object.

    [I sort of assumed everybody knew that. If that weren’t true, we wouldn’t need a COM identity rule. -Raymond]
  23. Jim says:

    App X: "Total everything failure: 0x80040005"

    Me: That’s soooo not helpful.

    I do so love it when even the most cosumer-oriented apps blurt out errors like that.

    In fact I’m sure Media Player gives an almost identical error code when what it actually means is, "Unable to play this movie with your installed codecs, try  downloading DivX or an AC3 audio codec." That was a fun bit of time on Google trying to get holiday videos playing for my mother.

    (note please don’t take this as a "But even MS get it wrong" post, the error just stuck out of the screen at me and reminded me of this)

  24. mattd says:

    “Igor: Market share numbers prove nothing. Is a Ford better than a Ferrari?”

    Stu: It’s about relevance, Windows is much more relevent than other OS’s. That is the point.

    [Apparently I wasn’t clear enough. Please take this argument somewhere else. Further off-topic comments will be deleted. -Raymond]
  25. Rick C says:

    Stu said "Market share numbers prove nothing. Is a Ford better than a Ferrari?"

    Well, the answer depends, like most real-world things.  Fords are far better at moving off the lot in large quantities.

Comments are closed.


*DISCLAIMER: I DO NOT OWN THIS CONTENT. If you are the owner and would like it removed, please contact me. The content herein is an archived reproduction of entries from Raymond Chen's "Old New Thing" Blog (most recent link is here). It may have slight formatting modifications for consistency and to improve readability.

WHY DID I DUPLICATE THIS CONTENT HERE? Let me first say this site has never had anything to sell and has never shown ads of any kind. I have nothing monetarily to gain by duplicating content here. Because I had made my own local copy of this content throughout the years, for ease of using tools like grep, I decided to put it online after I discovered some of the original content previously and publicly available, had disappeared approximately early to mid 2019. At the same time, I present the content in an easily accessible theme-agnostic way.

The information provided by Raymond's blog is, for all practical purposes, more authoritative on Windows Development than Microsoft's own MSDN documentation and should be considered supplemental reading to that documentation. The wealth of missing details provided by this blog that Microsoft could not or did not document about Windows over the years is vital enough, many would agree an online "backup" of these details is a necessary endeavor. Specifics include:

<-- Back to Old New Thing Archive Index