Board index » cppbuilder » COM server question

COM server question

I am writing an in-process server and have created a number of automation
objects.  Under normal circumstances the user will only need to create an
instance of one of these objects.  The other objects need to be created
within the dll, and made available to the client through pointers.  I also
need to be able to get at methods and properties that are not defined in the
interface for these objects.

My question is : How can I create instances of these other objects within
the dll and access the non-interface data?

So far I have tried:
* Creating an implementation class directly. This fails due to the
implementation class defining abstract methods.
* Using CoWhatever::Create() - this does not allow me to then get at the
private methods.

This is my first attempt at a COM app and I'm still figuring out what, and
how much Builder does for me and what I have to do myself.  I'm using BCB3,
but will be upgrading as soon as it arrives in NZ!

Thanks in advance

Martin.

 

Re:COM server question


I am writing an in-process server and have created a number of automation
objects.  Under normal circumstances the user will only need to create an
instance of one of these objects.  The other objects need to be created
within the dll, and made available to the client through pointers.  I also
need to be able to get at methods and properties that are not defined in the
interface for these objects.

My question is : How can I create instances of these other objects within
the dll and access the non-interface data?

So far I have tried:
* Creating an implementation class directly. This fails due to the
implementation class defining abstract methods.
* Using CoWhatever::Create() - this does not allow me to then get at the
private methods.

This is my first attempt at a COM app and I'm still figuring out what, and
how much Builder does for me and what I have to do myself.  I'm using BCB3,
but will be upgrading as soon as it arrives in NZ!

Thanks in advance

Martin.

Re:COM server question


I don't have a direct answer but I can point to some theory! This concept is
covered under Containment & Aggregation. Containment is when an inner class
is implemented as a property of an outer class. Aggregation is when the outer
class acts as an interface for inner class.

You may want to look thorugh Microsoft's knowledgebase or MSDN articles.
In article <922232986.228...@news.iconz.co.nz>,
  "Martin Welford" <mart...@trutest.co.nz> wrote:
[..]
 question is : How can I create instances of these other objects within

Quote
> the dll and access the non-interface data?

-- Sridhar

Sridhar Krishnan
Entek Systems, Inc.
http://www.enteksystems.com

-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/       Search, Read, Discuss, or Start Your Own    

Re:COM server question


Quote
Martin Welford wrote:

> I am writing an in-process server and have created a number of automation
> objects.  Under normal circumstances the user will only need to create an
> instance of one of these objects.  The other objects need to be created
> within the dll, and made available to the client through pointers.  I also
> need to be able to get at methods and properties that are not defined in the
> interface for these objects.

From the client?

You can't; not an option.

From within the server? You should be able to simply instantiate them
and then call the methods.

Quote
> So far I have tried:
> * Creating an implementation class directly. This fails due to the
> implementation class defining abstract methods.

Yeah; you'd need to actually define those methods rather than simply declaring
them.

Quote
> * Using CoWhatever::Create() - this does not allow me to then get at the
> private methods.

Sure; if you call CoCreateInstance, then you can only access what the Interface
gives you.

Quote
> This is my first attempt at a COM app and I'm still figuring out what, and
> how much Builder does for me and what I have to do myself.  I'm using BCB3,
> but will be upgrading as soon as it arrives in NZ!

The basic problem here is that you are trying to do mix regular C++ class
interaction with COM class interaction.

Re:COM server question


Aphrael,
No, you can't simply instantiate them.  As Martin first wrote:
* Creating an implementation class directly. This fails due to the
implementation class defining abstract methods.

Martin:

The MAIN problem is not really yours -- it's Borland's -- they provide ATL
but no ATL documentation.  You must have the MSDN Library (do you have VC++?
if so, you already have it, if not you can buy just the library portion OR
access it free of charge on http://msdn.microsoft.com/library).  I guess
they can license ATL but not the ATL docs, strange.  If this is MS's fault,
they should be sued! HA!

OK.  What you need to use is called CComObject.  It is a template class that
wraps an implementation CoClass to allow you to directly create instances of
it.  These instances can be given out as interface pointers to clients.
This is the normal way to do this sort of "internal instancing" where a
top-level class creates, on the clients' behalves, the other objects of the
Object Model.

Example: (I'm doing this mostly form memory in the hope that it will get you
started.)
/* Let's assume you have a class TInnerObjectImpl which is the CoClass for
your object which implements the custom interface IInnerObject. */
/* Let's also assume you have an "outer" class, TOuterObjectImpl, which the
client created and it provides a method which will return an IInnerObject
interface pointer to a newly created TInnerObject */

typedef CComObject<TInnerObjectImpl> TInnerObject;

IInnerObject*
STDMETHODCALLTYPE
TOuterObjectImpl::CreateNewInnerObject()
{
 TInnerObject* newObject = NULL;
 TInnerObject::CreateInstance(&newObject);
/* Using newObject->XXX we can access non-interface methods. */
/* Maybe private methods to initialize the new instance. */
/* Now we get the interface pointer to return to the client */
/* Remember that the refcount is still ZERO until we QueryInterface. */
 IInnerObject* pp = NULL;
 newObject->QueryInterface(IID_IInnerObject, (PVOID*)&pp);
 return pp;

Quote
}

I hope this helps you get started.

-Michael

Quote
aphrael <aphr...@burble.org> wrote in message

news:36F946D2.AA368B75@burble.org...
Quote

> Martin Welford wrote:

> > I am writing an in-process server and have created a number of
automation
> > objects.  Under normal circumstances the user will only need to create
an
> > instance of one of these objects.  The other objects need to be created
> > within the dll, and made available to the client through pointers.  I
also
> > need to be able to get at methods and properties that are not defined in
the
> > interface for these objects.

> From the client?

> You can't; not an option.

> From within the server? You should be able to simply instantiate them
> and then call the methods.

> > So far I have tried:
> > * Creating an implementation class directly. This fails due to the
> > implementation class defining abstract methods.

> Yeah; you'd need to actually define those methods rather than simply
declaring
> them.

> > * Using CoWhatever::Create() - this does not allow me to then get at the
> > private methods.

> Sure; if you call CoCreateInstance, then you can only access what the
Interface
> gives you.

> > This is my first attempt at a COM app and I'm still figuring out what,
and
> > how much Builder does for me and what I have to do myself.  I'm using
BCB3,
> > but will be upgrading as soon as it arrives in NZ!

> The basic problem here is that you are trying to do mix regular C++ class
> interaction with COM class interaction.

Re:COM server question


Maybe an example will help me understand this!

If a server has two automation objects defined - ITree and IApple, and ITree
defines a
* GrowApple method, and
* a pointer to an IApple

Apple has a colour propertry that is set when created by GrowApple, but is
read only on the IApple interface.

The client creates a tree object, calls GrowApple, and uses the pointer to
access the colour of the new Apple object.

How does the Tree object create the apple and initialise the Colour
property?

Quote
>The basic problem here is that you are trying to do mix regular C++ class
>interaction with COM class interaction.

Do you have to use an interface for all interaction between classes (COM
classes with COM classes & COM classes with C++ classes) within server?

Thanks

Martin.

Quote
aphrael wrote in message <36F946D2.AA368...@burble.org>...

>Martin Welford wrote:

>> I am writing an in-process server and have created a number of automation
>> objects.  Under normal circumstances the user will only need to create an
>> instance of one of these objects.  The other objects need to be created
>> within the dll, and made available to the client through pointers.  I
also
>> need to be able to get at methods and properties that are not defined in
the
>> interface for these objects.

>From the client?

>You can't; not an option.

>From within the server? You should be able to simply instantiate them
>and then call the methods.

>> So far I have tried:
>> * Creating an implementation class directly. This fails due to the
>> implementation class defining abstract methods.

>Yeah; you'd need to actually define those methods rather than simply
declaring
>them.

>> * Using CoWhatever::Create() - this does not allow me to then get at the
>> private methods.

>Sure; if you call CoCreateInstance, then you can only access what the
Interface
>gives you.

>> This is my first attempt at a COM app and I'm still figuring out what,
and
>> how much Builder does for me and what I have to do myself.  I'm using
BCB3,
>> but will be upgrading as soon as it arrives in NZ!

>The basic problem here is that you are trying to do mix regular C++ class
>interaction with COM class interaction.

Re:COM server question


Martin,

A COM  Interface is an abstract service. Such a service can be easily
related to an object as we know it but is not the object.

A COM class is a named set of these Interfaces in a DLL/EXE. A COM
object is an abstraction for whatever implements these interfaces in
the DLL/EXE. In your example, ITree and IGrow interfaces would be in
the same COM class; IApple would be in another.

Your ITree is just one of the service interfaces in a hypothetical COM
class named CLSID_Tree, for example. ITree is out on the end of the
lollipop; it is neither the tree object nor a surrogate for the class.

A COM object is not an object as we know it in C++ or any other object
oriented technology in the last 25 years. It is more fundamental. Ir
ia more abstract. It is focused on the interfaces.

For example, think of C++ classes TMyTree and TMyApple rather than
ITree and IApple. Then, provide a service IGrow as a wrapper for a set
of methods in TMyTree. The IGrow service interface need not be limited
to trees, but could possibly be used for feathers, fur and anything
else that could implement an IGrow interface.

You can model IGrow in C++ by a 100% pure abstract base class TMyGrow
that you inherit into TMyTree. Note that TMyGrow could be inherited
into TMyBird, TMyMammal or even TMyJunkPile.

The COM interface IGrow is a wrapper for TMyGrow. In IGrow, you will
need to move the normal return result into the argument of the IGrow
interface because every COM method returns an HRESULT to be tested.
Some people use the COM methods as they would the C++ methods, but
this is problematic -  the interface service classes and the object
model do not always map as cleanly as they do in this case.

OK, so how do you tell an IGrow for trees from an IGrow for birds? You
put them into different COM classes with different names such as
CLSID_Tree and CLSID_Bird.

If you use ATL, you will get default interfaces ITree, IDispatch, etc.
in default modules Tree.hpp/cpp inherited into a default C++ class
CTree that does most of the COM interfacing work for you. You will
override FinalConstruct() in class CTree to construct TMyTree. ITree
does little more

Interface IGrow will be in class CLSID_Tree. In ATL, you would make it
one of the base classes of CTree along with all the other interfaces
of CLSID_Tree. In CTree, IGrow methods wrapper the abstract class
TMyGrow, a base class of TMyTree to which you have a pointer; you
implement the virtual methods for TMyGrow in TMyTree.

Now, TMyGrow::get_IApple() can return the IApple interface of
CLSID_Apple through the IGrow::get_IApple(...) wrapper method. Note
that TMyTree might keep a list of instances of CLSID_Apple that it
creates. For each instance of CLSID_Apple, the local pointer to the
instance of TMyApple can be passed to TMyTree and they can talk
without using the COM  interface if they are in the same process space
and are thread safe relative to one another and external users, a
common situation for single-thread apartment (STA) components.

In summary, the pattern is to implement the COM interface requirements
in the COM classes generated by ATL and map them to C++ classes that
do the problem domain work like you would have otherwise. COM takes
care of all the system issues if used correctly. Exactly how to do
this is best determined by engineering your application wisely. I hope
this gives you the general idea of at least one way to do it.

Good luck,

Leo

On Thu, 25 Mar 1999 09:22:32 +1200, "Martin Welford"

Quote
<mart...@trutest.co.nz> wrote:
>Maybe an example will help me understand this!

>If a server has two automation objects defined - ITree and IApple, and ITree
>defines a
>* GrowApple method, and
>* a pointer to an IApple

>Apple has a colour propertry that is set when created by GrowApple, but is
>read only on the IApple interface.

>The client creates a tree object, calls GrowApple, and uses the pointer to
>access the colour of the new Apple object.

>How does the Tree object create the apple and initialise the Colour
>property?

>>The basic problem here is that you are trying to do mix regular C++ class
>>interaction with COM class interaction.

>Do you have to use an interface for all interaction between classes (COM
>classes with COM classes & COM classes with C++ classes) within server?

>Thanks

>Martin.

Re:COM server question


Sorry to reply to my own....

Martin,

It would be  better to make the method returning the interface a read-only
property.  This way you can return an HRESULT (like S_OK) to indicate an
error and put the returned interface into the out value of the property:

Use the typelibrary editor (pretty nice tool) to create a read-only property
under IOuterObject.  Name the property NewInnerObject.  Make the return type
"IInnerObject*".  Save (Ctl-S).  The typelibrary editor will produce a shell
method to be filled in named "get_NewInnerObject" in the TOuterObjectImpl
class.

/ / same typedef as before
typedef CComObject<TInnerObjectImpl> TInnerObject;

STDMETHODIMP TOuterObjectImpl::get_NewInnerObject(IInnerObject** Value)
{
 try
 {
  *Value = NULL;
  TInnerObject* newObject = NULL;
  TInnerObject::CreateInstance(&newObject);
  newObject->QueryInterface(IID_IInnerObject, (PVOID*)Value);
 }
 catch(Exception &e)
 {
  return Error(e.Message.c_str(), IID_IOuterObject);
 }
 return S_OK;

Quote
};
Michael G. <mich...@R.E.M.O.V.E.pickles.org> wrote in message

news:7dc0a4$oju10@forums.borland.com...
Quote
> Aphrael,
> No, you can't simply instantiate them.  As Martin first wrote:
> * Creating an implementation class directly. This fails due to the
> implementation class defining abstract methods.

> Martin:

> The MAIN problem is not really yours -- it's Borland's -- they provide ATL
> but no ATL documentation.  You must have the MSDN Library (do you have
VC++?
> if so, you already have it, if not you can buy just the library portion OR
> access it free of charge on http://msdn.microsoft.com/library).  I guess
> they can license ATL but not the ATL docs, strange.  If this is MS's
fault,
> they should be sued! HA!

> OK.  What you need to use is called CComObject.  It is a template class
that
> wraps an implementation CoClass to allow you to directly create instances
of
> it.  These instances can be given out as interface pointers to clients.
> This is the normal way to do this sort of "internal instancing" where a
> top-level class creates, on the clients' behalves, the other objects of
the
> Object Model.

> Example: (I'm doing this mostly form memory in the hope that it will get
you
> started.)
> /* Let's assume you have a class TInnerObjectImpl which is the CoClass for
> your object which implements the custom interface IInnerObject. */
> /* Let's also assume you have an "outer" class, TOuterObjectImpl, which
the
> client created and it provides a method which will return an IInnerObject
> interface pointer to a newly created TInnerObject */

> typedef CComObject<TInnerObjectImpl> TInnerObject;

> IInnerObject*
> STDMETHODCALLTYPE
> TOuterObjectImpl::CreateNewInnerObject()
> {
>  TInnerObject* newObject = NULL;
>  TInnerObject::CreateInstance(&newObject);
> /* Using newObject->XXX we can access non-interface methods. */
> /* Maybe private methods to initialize the new instance. */
> /* Now we get the interface pointer to return to the client */
> /* Remember that the refcount is still ZERO until we QueryInterface. */
>  IInnerObject* pp = NULL;
>  newObject->QueryInterface(IID_IInnerObject, (PVOID*)&pp);
>  return pp;
> }

> I hope this helps you get started.

> -Michael

> aphrael <aphr...@burble.org> wrote in message
> news:36F946D2.AA368B75@burble.org...

> > Martin Welford wrote:

> > > I am writing an in-process server and have created a number of
> automation
> > > objects.  Under normal circumstances the user will only need to create
> an
> > > instance of one of these objects.  The other objects need to be
created
> > > within the dll, and made available to the client through pointers.  I
> also
> > > need to be able to get at methods and properties that are not defined
in
> the
> > > interface for these objects.

> > From the client?

> > You can't; not an option.

> > From within the server? You should be able to simply instantiate them
> > and then call the methods.

> > > So far I have tried:
> > > * Creating an implementation class directly. This fails due to the
> > > implementation class defining abstract methods.

> > Yeah; you'd need to actually define those methods rather than simply
> declaring
> > them.

> > > * Using CoWhatever::Create() - this does not allow me to then get at
the
> > > private methods.

> > Sure; if you call CoCreateInstance, then you can only access what the
> Interface
> > gives you.

> > > This is my first attempt at a COM app and I'm still figuring out what,
> and
> > > how much Builder does for me and what I have to do myself.  I'm using
> BCB3,
> > > but will be upgrading as soon as it arrives in NZ!

> > The basic problem here is that you are trying to do mix regular C++
class
> > interaction with COM class interaction.

Re:COM server question


Thanks for the help.  These lines gave me the answer I was looking for:

Quote
> typedef CComObject<TInnerObjectImpl> TInnerObject;
> TInnerObject* newObject = NULL;
> TInnerObject::CreateInstance(&newObject);
> IInnerObject* pp = NULL;
> newObject->QueryInterface(IID_IInnerObject, (PVOID*)&pp);

I figured I needed to know about ATL but as you said, with no documentation
it makes it a little hard to know where to begin!

Thanks again

Martin.

Quote
Michael G. wrote in message <7dc0a4$oj...@forums.borland.com>...
>Aphrael,
>No, you can't simply instantiate them.  As Martin first wrote:
>* Creating an implementation class directly. This fails due to the
>implementation class defining abstract methods.

>Martin:

>The MAIN problem is not really yours -- it's Borland's -- they provide ATL
>but no ATL documentation.  You must have the MSDN Library (do you have
VC++?
>if so, you already have it, if not you can buy just the library portion OR
>access it free of charge on http://msdn.microsoft.com/library).  I guess
>they can license ATL but not the ATL docs, strange.  If this is MS's fault,
>they should be sued! HA!

>OK.  What you need to use is called CComObject.  It is a template class
that
>wraps an implementation CoClass to allow you to directly create instances
of
>it.  These instances can be given out as interface pointers to clients.
>This is the normal way to do this sort of "internal instancing" where a
>top-level class creates, on the clients' behalves, the other objects of the
>Object Model.

>Example: (I'm doing this mostly form memory in the hope that it will get
you
>started.)
>/* Let's assume you have a class TInnerObjectImpl which is the CoClass for
>your object which implements the custom interface IInnerObject. */
>/* Let's also assume you have an "outer" class, TOuterObjectImpl, which the
>client created and it provides a method which will return an IInnerObject
>interface pointer to a newly created TInnerObject */

>typedef CComObject<TInnerObjectImpl> TInnerObject;

>IInnerObject*
>STDMETHODCALLTYPE
>TOuterObjectImpl::CreateNewInnerObject()
>{
> TInnerObject* newObject = NULL;
> TInnerObject::CreateInstance(&newObject);
>/* Using newObject->XXX we can access non-interface methods. */
>/* Maybe private methods to initialize the new instance. */
>/* Now we get the interface pointer to return to the client */
>/* Remember that the refcount is still ZERO until we QueryInterface. */
> IInnerObject* pp = NULL;
> newObject->QueryInterface(IID_IInnerObject, (PVOID*)&pp);
> return pp;
>}

>I hope this helps you get started.

>-Michael

>aphrael <aphr...@burble.org> wrote in message
>news:36F946D2.AA368B75@burble.org...

>> Martin Welford wrote:

>> > I am writing an in-process server and have created a number of
>automation
>> > objects.  Under normal circumstances the user will only need to create
>an
>> > instance of one of these objects.  The other objects need to be created
>> > within the dll, and made available to the client through pointers.  I
>also
>> > need to be able to get at methods and properties that are not defined
in
>the
>> > interface for these objects.

>> From the client?

>> You can't; not an option.

>> From within the server? You should be able to simply instantiate them
>> and then call the methods.

>> > So far I have tried:
>> > * Creating an implementation class directly. This fails due to the
>> > implementation class defining abstract methods.

>> Yeah; you'd need to actually define those methods rather than simply
>declaring
>> them.

>> > * Using CoWhatever::Create() - this does not allow me to then get at
the
>> > private methods.

>> Sure; if you call CoCreateInstance, then you can only access what the
>Interface
>> gives you.

>> > This is my first attempt at a COM app and I'm still figuring out what,
>and
>> > how much Builder does for me and what I have to do myself.  I'm using
>BCB3,
>> > but will be upgrading as soon as it arrives in NZ!

>> The basic problem here is that you are trying to do mix regular C++ class
>> interaction with COM class interaction.

Other Threads