COM - One coclass with multiple interfaces or separate coclasses each with one interface ?

Posted on 2005-05-17
Last Modified: 2013-11-25
I am developing a Com Server that has two interfaces:-
1) Widgets - which is a STL Collection of Widget objects and
2) Widget - which encapsualtes the properties and methods of a Widget itself

I could implement this as one Coclass with 2 interfaces or 2 separate CoClasses in the Same COM Server.

What are the pros and cons of wither approach ? What influences that decision ?
Question by:ascot
    LVL 9

    Expert Comment

    Definitely two coclasses: one is a collection, the other is an instance.
    In fact, you would probably have three coclasses:
    - container with a read-only property that returns a COM interface pointer to the collection
    - collection of COM interface pointers to the items, and
    - item (Widget, in your case)

    If you want to also support automation/scripting, the standard approach is as follows:

    interface IWidget : IDispatch
          // methods and properties

    interface IWidgets : IDispatch
          [propget, id(DISPID_VALUE)] HRESULT Item([in] long nIndex, [out, retval] IWidget** ppIWidget);
          [propget, id(DISPID_NEWENUM)] HRESULT _NewEnum([out, retval] IUnknown** ppIEnumVARIANT);
                // returned pointer is actually a IEnumVARIANT (i.e. IID_IEnumVARIANT) but has to be declared as IUnknown to be able to use the standard marshaller
          [propget, id(1)] HRESULT Count([out, retval] long* pItemCount);

    interface IWidgetContainer : IDispatch
          [propget, id(1)] HRESULT Widgets([out, retval] IWidgets** ppIWidgets);
          // other methods and properties corresponding to the container

    This design will enable the use of the 'for-each' construct in languages that support it (e.g. VB, C#, Java, etc).


    Author Comment

    Thanks for a good answer.  I have the for-each construct working whether I use one coclass or 2 coclasses.
    I hadn't thought of the IWidgetContainer interface - how does this help ? What benefits does it provide ?

    Also re: "Definitely two coclasses" - why - why not one ?

    I've upped the points to 500 in order to get a full answer.

    Author Comment

    Also why     [propget, id(1)] HRESULT Widgets([out, retval] IWidgets** ppIWidgets);
    and not
    propget, id(1)] HRESULT Widgets([out, retval] IWidgets* pIWidgets);
    LVL 9

    Expert Comment

    One of the golden rules in COM design is to define complete yet minimalist interfaces. In other words, each interface should be fully functional, but it should not contain more methods or properties than what is really needed to implement and/or expose the required functionality. This is actually a general principle in OO design: keep refining your logical model until you get to atomic entities - which become your classes.

    A Widget and a collection of Widgets are two different concepts. As you said in your initial post: your Widgets have certain methods and properties. These expose the Widget service(s) to clients. A collection of Widgets, on the other hand, exposes different kinds of services - i.e. ability to enumerate over the collection, retrieve a particular Widget (e.g. identified by an index), find out the total number of Widgets in the collection, etc. Thus a different set of methods and properties than the individual Widgets.

    You can obviously have one coclass implementing more than one interface. However, this is generally discouraged because certain scripting languages are unable to specify what interface they want to use to talk to a given object. That's why there's a 'default' attribute, and most technical articles and books recommend a single IDispatch-based interface per coclass.

    So, both in terms of logical design and in terms of physical design, the two coclasses approach has clear advantages.

    The reason for a separate IWidgetContainer interface is that, in addition to the "standard" methods and properties required for the collection pattern, you may want to have other, domain specific, methods and/or properties. The name I used for it was just an example; you would most likely have something that reflects the actual role of this class in your domain (for example, it may be IToolbox). In addition to exposing the collection of widgets, the toolbox may have other properties (e.g. a type or a name). It may also have certain commands (e.g. open, close, add widget, etc). The IWidgets interface, as shown in my previous post, is the standard COM collection implementation - as expected by scripting languages, as well as high-level languages that have a ‘for-each’ construct (e.g. C#, VB, Java). Once again, following the 'complete yet minimalist' principle, it makes sense to split the two apart (i.e. two interfaces and, for the benefit of scripting languages, one interface per coclass – thus two coclasses).

    LVL 9

    Accepted Solution

    >>Also why     [propget, id(1)] HRESULT Widgets([out, retval] IWidgets** ppIWidgets);
    >>and not
    >>propget, id(1)] HRESULT Widgets([out, retval] IWidgets* pIWidgets);

    Because you need to return an IWidgets pointer (just like IUnknown::QueryInterface).


    Author Comment

    Wow - Thanks for taking the time to give a very complete answer describe in a very clear way.
    Excellent answer.

    Featured Post

    How your wiki can always stay up-to-date

    Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
    - Increase transparency
    - Onboard new hires faster
    - Access from mobile/offline

    Join & Write a Comment

    Suggested Solutions

    Title # Comments Views Activity
    hasOne  challenge 59 66
    bigHeights  challenge 13 43
    count7 challenge 12 53
    SQL400 max size 5 35
    Go is an acronym of golang, is a programming language developed Google in 2007. Go is a new language that is mostly in the C family, with significant input from Pascal/Modula/Oberon family. Hence Go arisen as low-level language with fast compilation…
    Does the idea of dealing with bits scare or confuse you? Does it seem like a waste of time in an age where we all have terabytes of storage? If so, you're missing out on one of the core tools in every professional programmer's toolbox. Learn how to …
    This video teaches viewers about errors in exception handling.
    Viewers will learn how to properly install Eclipse with the necessary JDK, and will take a look at an introductory Java program. Download Eclipse installation zip file: Extract files from zip file: Download and install JDK 8: Open Eclipse and …

    745 members asked questions and received personalized solutions in the past 7 days.

    Join the community of 500,000 technology professionals and ask your questions.

    Join & Ask a Question

    Need Help in Real-Time?

    Connect with top rated Experts

    16 Experts available now in Live!

    Get 1:1 Help Now