Tuesday, November 25, 2008

In ATL, you can't derive one coclass from another.

Click heading for discussion.
> I understand why you might want to have a deep hierarchy of
> implementation classes (this style was popular at one point - witness
> MFC - but has fallen out of fashion lately). But why would you want a
> deep hierarchy of _interfaces_?

Because the derived classes add additional functionality [and there must be a new interface to invoke the new functionality]. In my case--without going into irrelevant proprietary details--I have a 'painter' class that paints stuff, a 'control-base' class which implements a basic GUI control around the painted stuff, and a 'control' class which adds extra standard functionality.

Typically the user would either instantiate 'control-base' and customize it (picking and choosing the functionality desired and composing that functionality manually), or just use 'control' for a standard set of functionality. While I suppose this doesn't *have* to be designed as a hierarchy, the code was already written that way before I knew I would have to turn it into a COM component.

>You are busy confusing interface inheritance and implementation
>inheritance. These are two different things.

Actually I never confused the two, although I may have presented my thoughts in a highly confusing manner. Sorry about that! When I said IA and IB share a common interface, the common interface I meant was IA.

Anyway, I have now implemented my COM hierarchy and it's working great. Thanks for your help. I ended up doing pretty much what it says to do at http://vcfaq.mvps.org/com/8.htm -- to summarize what I did, I have

1. Implementation non-template classes A, B, and C (C derives from B derives from A) which don't necessarily use ATL or COM at all
2. COM interfaces IA, IB, IC (IC derives from IB derives from IA)
3. Wrapper classes CImpl<I>, BImpl<I> and AImpl<I> (CImpl<I> derives from BImpl<I> derives from AImpl<I> derives from I); AImpl<I> contains a pointer to an object of type A, B, or C depending on which ATL class is using it
4. ATL classes CA, CB, and CC which are totally separate and unrelated. CA, CB, and CC have base classes AImpl<IA>, BImpl<IB>, and CImpl<IC> respectively.

Monday, November 24, 2008

MIDL changing your property name to lowercase?

I had a "FileName" property in my interface...
interface IMyFile : IDispatch {
[propget, id(6)] HRESULT FileName([out, retval] BSTR* pVal);

and somehow in the TLB this came out as "filename" - all lowercase.

It turned out to be a really weird bug in MIDL. It was triggered because I had a method that takes a parameter called "filename". I had a method like this:
interface IMyFile : IDispatch {
[id(1)] HRESULT OpenFile(BSTR filename, long reserved);
[propget, id(6)] HRESULT FileName([out, retval] BSTR* pVal);

See, MIDL changes the case of the property (or method?) to match the case of the parameter. The solution was to rename the parameter "filename" to "FileName". This even happens if the matching parameter name appears in an unrelated interface!