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
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.