Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

IUnknown, Identity rule for 'nested objects'

13 views
Skip to first unread message

asno...@gmail.com

unread,
Oct 10, 2009, 8:54:43 PM10/10/09
to
A wrote an In-proc dll expsoing few nested objects. Today I was
reading DonBox book, and I think my object relation violates
'Indentity rule' so it may not work well when exposed as Out-proc
server or if there is any kind of marshalling. Seems like blunder that
I did. Hope you guys can confirm that....

interface IB : IDispatch
{
GetBColl(IBColl** pVal);
};

interface IN : IDispatch
{
GetT(IT** pVal);
GetB(IB** pVal);
GetEColl(IEColl** pVal);
};
interface IBColl : IDispatch
{
AddB( IB** v);
};


coclass N
{
[default] interface IN;
};

coclass B
{
[default] interface IB;
};

coclass BColl
{
[default] interface IBColl;
};

If CoClass-N is returning the a interface declared inside CoClass-B,
then according Idenitity rule they should both have same IUnknown.
Then only it is going survive marshalling. But in my case it is not.
Some pls confirm it. Another way of looking at iy is.
Does identity rule apply to interfaces within an CoClass?
If so, what happens when member of one CoClass returns interface of
some other CoClass?

Solutions:--
1) One solution that I can think is to apply 'Aggregate' relation
between these two CoClasses
2) Merge the interfaces of CoClassN & CoClassB

Identity rule and nested objects.....
---------------------------------------------------
Based on my understanding of Indentity rule, seems every object must
use "only one" IUknown that is of root-object. I do not know how how
difficult it to get aggregation working for 'nested' case, like the
one give below.
As you see here, oB is needs to be both 'aggregator' and
'aggregatee'.
------oN //root
-------------oB
----------------------oT

I have case of recursive relation between two objects, do not know how
to apply 'Aggregation'. I have asked several questions, hope someone
can help.

Thanks in advance..
Ramesh

Igor Tandetnik

unread,
Oct 10, 2009, 9:49:30 PM10/10/09
to
asno...@gmail.com wrote:
> If CoClass-N is returning the a interface declared inside CoClass-B,
> then according Idenitity rule they should both have same IUnknown.

COM identity rules are only about interface pointers returned by QueryInterface. It is perfectly fine, and quite common, to have a
method (other than QueryInterface) on one interface return an interface implemented by a different object with its own distinct COM
identity.
--
With best wishes,
Igor Tandetnik

With sufficient thrust, pigs fly just fine. However, this is not necessarily a good idea. It is hard to be sure where they are going
to land, and it could be dangerous sitting under them as they fly overhead. -- RFC 1925

asno...@gmail.com

unread,
Oct 11, 2009, 12:21:37 AM10/11/09
to
> COM identity rules are only about interface pointers returned by QueryInterface. It is perfectly fine, and quite common, to have a
> method (other than QueryInterface) on one interface return an interface implemented by a different object with its own distinct COM
> identity.
When you 'perfectly fine', are you also including the case where
Marshalling is involved?. My understanding is, marshallers call QI().
Let me give an example(x.dll),

CoClass A CoClassB
{ {
Interface IA1; Inteface IB1;
Interface IA2; Interface IB2;
}; };

Assume a method of IA1 returns pointer to IB1 by calling
CoCreateInstance(). Then marshaller may call like this. pIB1-
>QueryInterface(IID_IA!); In such case IB1 would not know about IA1.
In effect what I am is, does these COM rules like, Identity/
Transitivity/Reflexivity apply to just the interfaces "within"
coclass?

Following is my "main" concern, please comment on this.
In my in-proc DLL, every interface(dual) has its own CoClass, and
these interfaces are being created and returned by methods of other
coclass. I have not established 'Aggregation' among these CoClasses.
One among these CoClass, one is ROOT coclass. Now I have to expose
this In-proc dll though an Out-proc sever. And, inside Out-proc
server, I have just one method, to return that root coclass of DLL,
like following,

COutProc::GetInProcServer( IRootOfDll** pVal) //This EXE
{
CoCreateInstance(CLSID_RootOfDll,.....pVal); //This is
Dll
}
Once, caller gets pVal, he will fetch other interfaces, implemented
inside Dll. DonBox book, under Binary-Composition has similar example
and says 'Aggregation' should be used to let IRootOfDll know that it
is being used. Then I flashed to me that, to survive Marshalling,
'Aggregation' is needed not just in the above function(in EXE) but
also among the CoClasses that are inside Dll. Even if I use
'containment' and duplicate the DLL's object heirarchy inside EXE, I
may still have to bolster this containment wrapper with 'aggregation'.
These are the things that I would like to get clarified these concept
before I start implementing solution.

My another major conecern is, applying aggregation to multi-layered
"parent-child" object. I do not even know whether this is possible.


Thanks for responding.
Ramesh


On Oct 10, 9:49 pm, "Igor Tandetnik" <itandet...@mvps.org> wrote:

Igor Tandetnik

unread,
Oct 11, 2009, 10:30:30 AM10/11/09
to
asno...@gmail.com wrote:
>> COM identity rules are only about interface pointers returned by
>> QueryInterface. It is perfectly fine, and quite common, to have a
>> method (other than QueryInterface) on one interface return an
>> interface implemented by a different object with its own distinct
>> COM identity.
> When you 'perfectly fine', are you also including the case where
> Marshalling is involved?

Yes I am.

> My understanding is, marshallers call QI().

Yes, they sometimes do.

> Let me give an example(x.dll),
>
> CoClass A CoClassB
> { {
> Interface IA1; Inteface IB1;
> Interface IA2; Interface IB2;
> }; };
>
> Assume a method of IA1 returns pointer to IB1 by calling
> CoCreateInstance(). Then marshaller may call like this. pIB1-
>> QueryInterface(IID_IA!);

No. Why would it do that? What reason it has to believe that CoClassB is in any way related to or aware of IA?

> In such case IB1 would not know about IA1.

And rightly so.

> In effect what I am is, does these COM rules like, Identity/
> Transitivity/Reflexivity apply to just the interfaces "within"
> coclass?

Yes.

> Following is my "main" concern, please comment on this.

If you insist.

> In my in-proc DLL, every interface(dual) has its own CoClass, and
> these interfaces are being created and returned by methods of other
> coclass.

A perfectly reasonable arrangement, generally known as an object hierarchy.

> I have not established 'Aggregation' among these CoClasses.

Wise decision.

> One among these CoClass, one is ROOT coclass. Now I have to expose
> this In-proc dll though an Out-proc sever. And, inside Out-proc
> server, I have just one method, to return that root coclass of DLL,

You may have some difficulty figuring out when that out-of-proc server is safe to shut down. You don't want to terminate it while
there are still outstanding references to objects inside the DLL it hosts. I suppose you could check DllCanUnloadNow periodically.

> Once, caller gets pVal, he will fetch other interfaces, implemented
> inside Dll. DonBox book, under Binary-Composition has similar example
> and says 'Aggregation' should be used

You are not doing composition, so that chapter doesn't apply. Composition is a technique whereby two or more objects (either
source-level classes or binary components) cooperate to pretend to be a single COM component (more formally, maintain a single COM
identity). Nothing in your problem statement suggests that you may need or want that.

> to let IRootOfDll know that it is being used.

Why does it care?

> Then I flashed to me that, to survive Marshalling,
> 'Aggregation' is needed not just in the above function(in EXE) but
> also among the CoClasses that are inside Dll.

In your mind, what precisely is the mechanism by which marshalling would "kill" your arrangement, so that steps to assure "survival"
must be taken?

Have you tried a straightforward implementation? Did it not work for you? In what way did it fail?

> Even if I use
> 'containment' and duplicate the DLL's object heirarchy inside EXE, I
> may still have to bolster this containment wrapper with 'aggregation'.

Because otherwise... ?

> These are the things that I would like to get clarified these concept
> before I start implementing solution.

I hope I was able to alleviate your concerns.

> My another major conecern is, applying aggregation to multi-layered
> "parent-child" object. I do not even know whether this is possible.

It doesn't make any sense to even try.

asno...@gmail.com

unread,
Oct 11, 2009, 2:22:11 PM10/11/09
to
> > In effect what I am is, does these COM rules like, Identity/
> > Transitivity/Reflexivity apply to just the interfaces "within"
> > coclass?
> Yes.
Thanks, this clears all of my doubts, I did not know this key
information.

> You may have some difficulty figuring out when that out-of-proc server is safe to shut down. You don't want to terminate it while
> there are still outstanding references to objects inside the DLL it hosts. I suppose you could check DllCanUnloadNow periodically.

My understanding is you are referring to EXE prematurely shutting
down, and to avoid that EXE should invoke DllCanUnloadNow() of
embedded dll.
At present I do not have that, and following is my current
implementation; as you can see I am not calling AddRef(). Callers of
this Out-proc is mostly C# applications.

IDL for EXE
-----------------
#import ("abc.tlb"); // this to import the DLL
interface Factory
{
CreateAbcInstance(IAbc** ppVal);
}

CExe::CreateAbcInstance( IAbc** ppVal)
{
hr = CoCreateInstance(CLSID_Abc, 0, ALL, IID_IAbc, ppVal); //
Here I am not calling AddRef(), thought that caller's Release() would
take care.
//
I am not sure whether I have to call AddRef() and Relase() in the end.
}

> Have you tried a straightforward implementation? Did it not work for you? In what way did it fail?

Yes, I have a simple implementation already(as shown above). I was not
confident about what I had done because this is the first time I am
dealing with mutiple objects, wrapping dll inside another Out-proc
server. My initial implementation gave proble: 'enum' values passed-in
(from client), through IAbc member's had wrong value on their arrival
at Abc.dll. To fix this, I had to remove _MERGE_PROXY preprocessor
from both Abc.dll and EXE, and that resulted in them using using
'Universal Marshaller'. ProxyStubClsid32 = {00020424-0000-0000-
C000-000000000046} With this change things have been working. In my
IDL file, interfaces declarations are outside Library{} section, and I
do not think this has any effect because I am not using CustomProxy
anymore.

When I searched for IID of my interface I found this
{aaaa-bbbb-} default=PSFactoryBuffer'
{aaaa-bbbb-}\InprocServer32 default=C:\...\adbc.dll
I am curious what this PSFactoryBuffer' is doing.


Thanks for responding with patience,
Ramesh


On Oct 11, 10:30 am, "Igor Tandetnik" <itandet...@mvps.org> wrote:

0 new messages