Holy cow, I wrote a book!
One of the more subtle ways
people mess up IUnknown::QueryInterface
when the problem wasn't actually an unsupported interface.
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
Recall that the rules for
are that (in the absence of catastrophic errors such as
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
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.
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.