?
Solved

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

Posted on 2005-05-17
6
Medium Priority
?
826 Views
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 ?
0
Comment
Question by:ascot
  • 3
  • 3
6 Comments
 
LVL 9

Expert Comment

by:rcarlan
ID: 14018534
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).

Radu
0
 

Author Comment

by:ascot
ID: 14018806
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.
0
 

Author Comment

by:ascot
ID: 14018965
Also why     [propget, id(1)] HRESULT Widgets([out, retval] IWidgets** ppIWidgets);
and not
propget, id(1)] HRESULT Widgets([out, retval] IWidgets* pIWidgets);
0
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 9

Expert Comment

by:rcarlan
ID: 14019235
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).

Radu
0
 
LVL 9

Accepted Solution

by:
rcarlan earned 2000 total points
ID: 14019261
>>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).

Radu
0
 

Author Comment

by:ascot
ID: 14025329
Wow - Thanks for taking the time to give a very complete answer describe in a very clear way.
Excellent answer.
0

Featured Post

Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

In real business world data are crucial and sometimes data are shared among different information systems. Hence, an agreeable file transfer protocol need to be established.
Article by: evilrix
Looking for a way to avoid searching through large data sets for data that doesn't exist? A Bloom Filter might be what you need. This data structure is a probabilistic filter that allows you to avoid unnecessary searches when you know the data defin…
The viewer will learn how to use the return statement in functions in C++. The video will also teach the user how to pass data to a function and have the function return data back for further processing.
The viewer will be introduced to the member functions push_back and pop_back of the vector class. The video will teach the difference between the two as well as how to use each one along with its functionality.
Suggested Courses
Course of the Month15 days, 3 hours left to enroll

839 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