Board index » cppbuilder » Passing a COM interface to another COM Interface

Passing a COM interface to another COM Interface

I have created two COM objects, one in Delphi and the other in BCB 6.  I
wish to pass the Delphi COM object (as an interface) to the C COM object and
store it there.  However I have problems storing the interface - the
interface works correctly when not in a variable, i.e.

C_COM_Object :: AddDevice( IDevice ADevice)
{
    FDevice = ADevice;

    FDevice -> DisplayMessage();
    //Works OK

Quote
};//C_COM_Object :: AddDevice( IDevice ADevice)

C_COM_Object :: AnotherMethod()
{
    FDevice -> DisplayMessage();
    //Doesn't work and throws an error

Quote
};//C_COM_Object :: AnotherMethod()

I have done eactly the same thing in Delphi and it works OK.  Any ideas
anyone?
 

Re:Passing a COM interface to another COM Interface


Quote
"Matt" <matth...@simstor.co.uk> wrote in message

news:3eafe459@newsgroups.borland.com...

Quote
> C_COM_Object :: AddDevice( IDevice ADevice)
> {
>     FDevice = ADevice;

What is FDevice declared as exactly?  If not based on a smart pointer
(DelphiInterface or TComInterface), but just a raw pointer, then you must
call ADevice->AddRef() manually.  Otherwise you're not incrementing the
interface's reference count, and the caller may be freeing the interface
after AddDevice() returns.  That would explain why AnotherMethod() failed -
the interface was no longer valid:

    C_COM_Object :: AddDevice( IDevice *ADevice)
    {
        FDevice = ADevice;
        FDevice->AddRef();
    }

Then later on, you need to release the interface as some point:

    FDevice->Release();

Gambit

Re:Passing a COM interface to another COM Interface


Thankyou for your advice Gambit, after inserting the AddRef call it worked
immediately.  However I have concerns about the solution.

FDevice as you correctly guessed is a raw pointer to a IDevice - each
IDevice COM object created passes itself to the C_COM_Object using the
AddDevice method (it is to be used for a multi-dropped comms port) I am
certain that the IDevice has not freed itself (as the form owning it is
still displayed on the screen and I have a breakpoint on the destructor) so
why do I need to call AddRef?

Why would this work in Delphi without the AddRef call needed but not in C?

When I pass an interface to one COM object to another is just a pointer
passed?  Or is the COM mechanism passing more than just a memory address?  I
ask this as when using DCOM more info will need to be passed.

Please excuse my naivety as this is my first serious COM project so have
very little understanding of the theory.

Thanks in advance

    Matt.

Re:Passing a COM interface to another COM Interface


Quote
"Matt" <matth...@simstor.co.uk> wrote in message

news:3eb147c8@newsgroups.borland.com...

Quote
> I am certain that the IDevice has not freed itself (as the form
> owning it is still displayed on the screen and I have a
> breakpoint on the destructor) so why do I need to call AddRef?

As previous mentioned, COM interfaces are reference counted.  The count is
initially 0, and is incremented everytime AddRef() is called.  You need to
call AddRef() to keep the reference count above 0 so the interface stays
alive while you're still using it.  As soon as the count drops to 0, the
interface must free itself automatically.  Whenever you are done using an
interface, you must Release() it so the reference count decrements properly.
It sounds like your C_COM_Object class is never calling FDevice->Release()
when it is done with FDevice and doesn't need it anymore.

It should also be mentioned that your AddDevice() method has another design
flaw in it - if AddDevice() is called multiple times, you are not
Release()'ing the existing FDevice before reassigning it.  You need to do
that as well.

So, for example:

    C_COM_Object::C_COM_Object()
    {
        FDevice = NULL;
    }

    C_COM_Object::~C_COM_Object()
    {
        if( FDevice )
            FDevice->Release();
    }

    C_COM_Object :: AddDevice(IDevice *ADevice)
    {
        if( FDevice )
            FDevice->Release();

        FDevice = ADevice;

        if( FDevice )
        {
            FDevice->AddRef();
            FDevice -> DisplayMessage();
        }
    }

    C_COM_Object::AnotherMethod()
    {
        if( FDevice )
            FDevice->DisplayMessage();
    }

The easiest way to work around all of these reference counting issues is to
not use a raw pointer for your FDevice member to begine with.  Declare your
FDevice member using either the DelphiInterface or TComInterface wrapper
class.  That way, the reference counting is handled automatically for you:

    class C_COM_Object : ...
    {
    private:
        Delphinterface<IDevice> FDevice;
    };

    C_COM_Object :: AddDevice(IDevice *ADevice)
    {
        FDevice = ADevice;
        if( FDevice )
            FDevice -> DisplayMessage();
    }

    C_COM_Object::AnotherMethod()
    {
        if( FDevice )
            FDevice->DisplayMessage();
    }

Quote
> Why would this work in Delphi without the AddRef call needed but not in C?

Becaise the Delphi Pascal language has native support for interfaces and it
handles the reference counting for you behind the scenes.

Quote
> When I pass an interface to one COM object to another
> is just a pointer passed?

More or less, yeah.

Gambit

Re:Passing a COM interface to another COM Interface


I think that I understand it now.

Cheers for your time.

"Remy Lebeau (TeamB)" <gambi...@yahoo.com> wrote in message
news:3eb1626a$1@newsgroups.borland.com...

Quote

> "Matt" <matth...@simstor.co.uk> wrote in message
> news:3eb147c8@newsgroups.borland.com...

> > I am certain that the IDevice has not freed itself (as the form
> > owning it is still displayed on the screen and I have a
> > breakpoint on the destructor) so why do I need to call AddRef?

> As previous mentioned, COM interfaces are reference counted.  The count is
> initially 0, and is incremented everytime AddRef() is called.  You need to
> call AddRef() to keep the reference count above 0 so the interface stays
> alive while you're still using it.  As soon as the count drops to 0, the
> interface must free itself automatically.  Whenever you are done using an
> interface, you must Release() it so the reference count decrements
properly.
> It sounds like your C_COM_Object class is never calling FDevice->Release()
> when it is done with FDevice and doesn't need it anymore.

> It should also be mentioned that your AddDevice() method has another
design
> flaw in it - if AddDevice() is called multiple times, you are not
> Release()'ing the existing FDevice before reassigning it.  You need to do
> that as well.

> So, for example:

>     C_COM_Object::C_COM_Object()
>     {
>         FDevice = NULL;
>     }

>     C_COM_Object::~C_COM_Object()
>     {
>         if( FDevice )
>             FDevice->Release();
>     }

>     C_COM_Object :: AddDevice(IDevice *ADevice)
>     {
>         if( FDevice )
>             FDevice->Release();

>         FDevice = ADevice;

>         if( FDevice )
>         {
>             FDevice->AddRef();
>             FDevice -> DisplayMessage();
>         }
>     }

>     C_COM_Object::AnotherMethod()
>     {
>         if( FDevice )
>             FDevice->DisplayMessage();
>     }

> The easiest way to work around all of these reference counting issues is
to
> not use a raw pointer for your FDevice member to begine with.  Declare
your
> FDevice member using either the DelphiInterface or TComInterface wrapper
> class.  That way, the reference counting is handled automatically for you:

>     class C_COM_Object : ...
>     {
>     private:
>         Delphinterface<IDevice> FDevice;
>     };

>     C_COM_Object :: AddDevice(IDevice *ADevice)
>     {
>         FDevice = ADevice;
>         if( FDevice )
>             FDevice -> DisplayMessage();
>     }

>     C_COM_Object::AnotherMethod()
>     {
>         if( FDevice )
>             FDevice->DisplayMessage();
>     }

> > Why would this work in Delphi without the AddRef call needed but not in
C?

> Becaise the Delphi Pascal language has native support for interfaces and
it
> handles the reference counting for you behind the scenes.

> > When I pass an interface to one COM object to another
> > is just a pointer passed?

> More or less, yeah.

> Gambit

Other Threads