The ways people mess up IUnknown::QueryInterface

Raymond Chen

Raymond

When you’re dealing with application compatibility,
you discover all sorts of things that worked only by accident.
Today, I’ll talk about some of the “creative” ways people
mess up the

IUnknown::QueryInterface method
.

Now, you’d think, “This interface is so critical to COM,
how could anybody possible mess it up?”

Forgetting to respond to IUnknown.

Sometimes you get so excited about responding to all these
great interfaces that you forget to respond to IUnknown itself.
We have found objects where

IShellFolder *psf = some object;
IUnknown *punk;
psf->QueryInterface(IID_IUnknown, (void**)&punk);

fails with E_NOINTERFACE!

Forgetting to respond to your own interface.

There are some methods which return an object with a specific
interface. And if you query that object for its own interface,
its sole reason for existing, it says “Huh?”

IShellFolder *psf = some object;
IEnumIDList *peidl, *peidl2;
psf->EnumObjects(..., &peidl);
peidl->QueryInterface(IID_IEnumIDList, (void**)&peidl2);

There are some objects which return E_NOINTERFACE to the QueryInterface
call, even though you’re asking the object for itself!
“Sorry, I don’t exist,” it seems they’re trying to say.

Forgetting to respond to base interfaces.

When you implement a derived interface, you implicitly implement
the base interfaces, so don’t forget to respond to them, too.

IShellView *psv = some object;
IOleView *pow;
psv->QueryInterface(IID_IOleView, (void**)&pow);

Some objects forget and the QueryInterface fails with E_NOINTERFACE.

Requiring a secret knock.

In principle, the following two code fragments are equivalent:

IShellFolder *psf;
IUnknown *punk;
CoCreateInstance(CLSID_xyz, ..., IID_IShellFolder, (void**)&psf);
psf->QueryInterface(IID_IUnknown, (void**)&punk);
CoCreateInstance(CLSID_xyz, ..., IID_IUnknown, (void**)&punk);
punk->QueryInterface(IID_IShellFolder, (void**)&psf);

In reality, some implementations mess up and fail the second call
to CoCreateInstance. The only way to create the object successfully
is to create it with the IShellFolder interface.

Forgetting to say “no” properly.

One of the rules for saying “no” is that you have to set the
output pointer to NULL before returning. Some people forget to do
that.

IMumble *pmbl;
punk->QueryInterface(IID_IMumble, (void**)&pmbl);

If the QueryInterface succeeds, then pmbl must be non-NULL on return.
If it fails, then pmbl must be NULL on return.

The shell has to be compatible with all these buggy objects because
if it weren’t, customers would get upset and the press would have
a field day. Some of the offenders
are big-name programs. If they broke, people would report,
“Don’t upgrade to Windows XYZ, it’s not compatible with
<big-name program>.”
Conspiracy-minded folks would shout,
“Microsoft intentionally broke <big-name program>!
Proof of unfair business tactics!”

[Raymond is currently on vacation; this message was pre-recorded.]

Raymond Chen
Raymond Chen

Follow Raymond   

0 comments

Comments are closed.