Hi Robert,
> Is there any way to mark a .NET interop class as non-aggregatable? My .NET
> classes are being instantiated as aggegatable objects by 3rd party COM
> objects, and when they're passed around to my other .NET objects they're
> being passed as __ComObject because the Marshaler can't figure out what to do
> with them. When they're instantiated without an outer unknown, they work
> fine. (using VS.NET 2003/2005)
This behavior is by design: the aggregation hides the identity of
your object. The object passed back is not the object that was
created by the runtime.
When the aggregator does "blind aggregation", you may be able to
cast the object to one of its interfaces.
I think the aggregation could be controlled with
System.Runtime.InteropServices.ExtensibleClassFactory.
You have to apply the code on all classes that get eaten by
the COM object.
(Untested)
[ComVisile(true)]
public class A {
const int CLASS_E_NOAGGREGATION = unchecked((int)0x80040110);
static A {
ExtensibleClassFactory.RegisterObjectCreationCallback(
new ObjectCreationDelegate(Create));
}
static IntPtr Create(IntPtr aggregator) {
if (aggregator != IntPtr.Zero) {
// we don't want to be agg*ted
throw new COMException("", CLASS_E_NOAGGREGATION)
}
else {
// create a new instance and return its CCW
return Marshal.GetIUnknownForObject(new A());
}
}
public A() {
}
}
bye
Rob
Robert Simpson - 27 Oct 2004 02:55 GMT
Well, that explains a lot. I'll try fiddling with your example and see if it
solves my problem.
In my case, the .NET object is an ActiveX control. The ActiveX Test
Container aggregates it and does indeed do "mostly" blind delegation to the
inner object. I've tried everything I can think of to get to the inner
object from my other .NET objects without success. I've implemented
interfaces and queried for them, even made methods that are supposed to
return the class object ... but they invariably return __ComObject, invalid
cast exceptions or NULL when using the "as" keyword.
> Hi Robert,
>
[quoted text clipped - 46 lines]
> bye
> Rob
Robert Simpson - 27 Oct 2004 15:53 GMT
Well, I messed around with that briefly, and after testing and reading the
MSDN documentation on the ExtensibleClassFactory, it was clear that solution
wasn't going to work.
The ExtensibleClassFactory only provides callback functionality for classes
that derive from COM imported classes. It will not allow you to customize
how your non-COM based .NET class is constructed through COM.
For the record, this is the error message when you try and register the
creation callback: "Function can only be called from inside the class
constructor of a class derived from a COM imported class"
> Hi Robert,
>
[quoted text clipped - 46 lines]
> bye
> Rob
Robert Jordan - 28 Oct 2004 00:58 GMT
Hi Robert,
> Well, I messed around with that briefly, and after testing and reading the
> MSDN documentation on the ExtensibleClassFactory, it was clear that solution
[quoted text clipped - 7 lines]
> creation callback: "Function can only be called from inside the class
> constructor of a class derived from a COM imported class"
Sorry, I didn't tested the code. The best part of the documentation
seems to be the exception message :-/
Did you already tried a late-bind call on the returned __ComObject?
Implement a property:
public YourForm Instance {
get { return this; }
}
Now the late-bind call on the unknown object:
YourForm f = (YourForm) unk.GetType().InvokeMember(
"Instance",
BindingFlags.Instance | BindingFlags.GetProperty,
null,
unk,
null
);
However, this could only work when the IDispatch implementation
of the aggregator would forward this call to the inner
object.
bye
Rob
Robert Simpson - 28 Oct 2004 18:09 GMT
No such luck -- the outer object intercepts IDispatch -- and even if I did
manage to get to the inner dispatch, during the return trip marshaling
process it queries the returned value from that property for IUnknown, which
again grabs the outer unknown and passes it onto me as __ComObject.
> Sorry, I didn't tested the code. The best part of the documentation
> seems to be the exception message :-/
[quoted text clipped - 23 lines]
> bye
> Rob
AH HA! I finally got it!
The trick was to use an interface with a property (as you had suggested) but
instead of returning the object or late-binding invoke to get the object, the
trick is to wrap the object in an ObjectHandle() class and unwrap it on the
receiving side.
Alternatively, I was able to return any MarshalByRef object that then in
turn exposed a property which returned the actual object I was trying to get
in the first place.
> Is there any way to mark a .NET interop class as non-aggregatable? My .NET
> classes are being instantiated as aggegatable objects by 3rd party COM
[quoted text clipped - 4 lines]
>
> Help!