How to expose IDispatch on an internal class

  • Thread starter Thread starter Marvin Landman
  • Start date Start date
M

Marvin Landman

Hi,

I would like to expose some objects using COM to native code.

My problem is that IDispatch seems to require the class to be public to
work.

I have a class with an interface, both are internal.

[System.Runtime.InteropServices.ComDefaultInterface (typeof (IMyInterface))]
[System.Runtime.InteropServices.ClassInterface
(System.Runtime.InteropServices.ClassInterfaceType.None)]
[System.Runtime.InteropServices.ComVisible (true)]
internal class MyClass : IMyInterface

[System.Runtime.InteropServices.InterfaceType
(System.Runtime.InteropServices.ComInterfaceType.InterfaceIsDual)]
internal interface IMyInterface

This succeeds:
System.Runtime.InteropServices.Marshal.GetComInterfaceForObject(myobjectoftypemyclass,
typeof(IMyInterface));

This results in InvalidCastException:
System.Runtime.InteropServices.Marshal.GetIDispatchForObject
(myobjectoftypemyclass);

This could work but the native side explicitly requests and IDispatch
interface so I get the exception (as a HResult) even if I pass the
result of GetComInterfaceForObject.

If I make MyClass public the problem is solved. But I would like to keep
MyClass internal and expose IMyInterface as its IDispatch interface.

Thank you.

Regards,
Marvin
 
Hello Marvin,

From your code I saw you're currently defining your interface as
InterfaceIsDual. If you want to expose it as IDispatch, could you try
define the InterfaceType as IDispatch?

Please kindly let me know how it goes.

Thanks,
Jie Wang

Microsoft Online Community Support

Delighting our customers is our #1 priority. We welcome your comments and
suggestions about how we can improve the support we provide to you. Please
feel free to let my manager know what you think of the level of service
provided. You can send feedback directly to my manager at:
(e-mail address removed).

==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/en-us/subscriptions/aa948868.aspx#notifications.

Note: MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 2 business days is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions. Issues of this
nature are best handled working with a dedicated Microsoft Support Engineer
by contacting Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/en-us/subscriptions/aa948874.aspx
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
Hi Jie,

Thank you very much for your reply.

I actually would prefer to use InterfaceIsDual and I belive that it
should be 100% compatible with InterfaceIsIDispatch as well as providing
an interface for "early binding". Note that I've tried IDispatch as well
and I got exactly the same results regarding my test case as described.

Thanks.

Marvin
 
Hi Marvin,

What is the client of the component? VB6? Native VC++? Or something else?

Please let me know more about the detailed configuration so I can try repro
the scenario and find out more.

Thanks,
Jie Wang

Microsoft Online Community Support

Delighting our customers is our #1 priority. We welcome your comments and
suggestions about how we can improve the support we provide to you. Please
feel free to let my manager know what you think of the level of service
provided. You can send feedback directly to my manager at:
(e-mail address removed).

==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/en-us/subscriptions/aa948868.aspx#notifications.

Note: MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 2 business days is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions. Issues of this
nature are best handled working with a dedicated Microsoft Support Engineer
by contacting Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/en-us/subscriptions/aa948874.aspx
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
Hi,

The client component is Windows Script Host, but I was able to reproduce
the same problem by using GetIDispatchForObject that I believe is
calling the same internal marshaling function as the automatic marshaler.

My problem is that I get InvalidCastException for
"Marshal.GetIDispatchForObject (mc)"

When I change "internal class MyClass : IMyInterface" to "public class
MyClass : IMyInterface" the exception is gone and everything works as
expected.

My problem is that I would like to expose the IDispatch object to COM
componenets (Windows Script Host) but I don't want to expose those
objects to managed applications.

using System;
using System.Runtime.InteropServices;

namespace InternalIDispatch
{
[ClassInterface (ClassInterfaceType.None)]
[ComVisible (true)]
internal class MyClass : IMyInterface
{
public void MyMethod ()
{
Console.WriteLine ("MyMethod");
}
}

[InterfaceType (ComInterfaceType.InterfaceIsDual)]
internal interface IMyInterface
{
void MyMethod ();
}

internal class Program
{
private static void Main (string [] args)
{
MyClass mc = new MyClass ();

Console.WriteLine (Marshal.GetIDispatchForObject (mc));
Console.ReadLine ();
}
}
}


Thanks.

Marvin
 
Hi Marvin,

Sorry for the late reply.

It seems we both missed a very important point here: to expose your managed
type to COM, the type must be public.

As it is described in "Qualifying .NET Types for Interoperation":

*** Quote ***

Managed types must be public.

Only public types in an assembly are registered and exported to the type
library. As a result, only public types are visible to COM.

*** End Quote ***

The link to the article:
http://msdn.microsoft.com/en-us/library/7fcfby2t.aspx

So it is clear that you must make the types public if you want them usable
from COM clients.

Please let me know if any questions.

Best regards,
Jie Wang

Microsoft Online Community Support

Delighting our customers is our #1 priority. We welcome your comments and
suggestions about how we can improve the support we provide to you. Please
feel free to let my manager know what you think of the level of service
provided. You can send feedback directly to my manager at:
(e-mail address removed).

==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/en-us/subscriptions/aa948868.aspx#notifications.

Note: MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 2 business days is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions. Issues of this
nature are best handled working with a dedicated Microsoft Support Engineer
by contacting Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/en-us/subscriptions/aa948874.aspx
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
Hi,
It seems we both missed a very important point here: to expose your managed
type to COM, the type must be public.

Thank you very much for finding out this limitation.

I am however confused because

Console.WriteLine (Marshal.GetIUnknownForObject (mc));

works just fine even when both the class and the interface are private.

Marvin
 
Hi Marvin,

I'm not very sure about what's going on under the hood of the Get*ForObject
methods. But if you don't mind, I can take some time and try find someone
does know. Then I'll update here.

Regards,
Jie Wang

Microsoft Online Community Support

Delighting our customers is our #1 priority. We welcome your comments and
suggestions about how we can improve the support we provide to you. Please
feel free to let my manager know what you think of the level of service
provided. You can send feedback directly to my manager at:
(e-mail address removed).

==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/en-us/subscriptions/aa948868.aspx#notifications.

Note: MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 2 business days is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions. Issues of this
nature are best handled working with a dedicated Microsoft Support Engineer
by contacting Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/en-us/subscriptions/aa948874.aspx
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
Hi,
I'm not very sure about what's going on under the hood of the Get*ForObject
methods. But if you don't mind, I can take some time and try find someone
does know. Then I'll update here.

I would appreciate if you could do that for me.

Thank you.

Regards,
Marvin
 
Hi Marvin,

Just want you to know that it took longer than I expected to reach the
source, it might take some more days. If you are not okay with that, please
let me know and I'll try some other ways.

Thanks,
Jie Wang

Microsoft Online Community Support

Delighting our customers is our #1 priority. We welcome your comments and
suggestions about how we can improve the support we provide to you. Please
feel free to let my manager know what you think of the level of service
provided. You can send feedback directly to my manager at:
(e-mail address removed).

==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/en-us/subscriptions/aa948868.aspx#notifications.

Note: MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 2 business days is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions. Issues of this
nature are best handled working with a dedicated Microsoft Support Engineer
by contacting Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/en-us/subscriptions/aa948874.aspx
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
Hi Marvin,

Here is the answer to your question.
I am however confused because
Console.WriteLine (Marshal.GetIUnknownForObject (mc));
works just fine even when both the class and the interface are private.


Marshal.GetIDispatchForObject QI (QueryInterface) IDispatch on the CCW
(ComCallableWrapper) of the object. Since MyClass is attributed to
ClassInterfaceType.None, it does not have the IDispatch implementation by
CLR, which further fails the QI. QI is the cast operation used in COM. It
makes sense to map the error to InvalidCastOperation.

Similarly, Marshal.GetIUnknow trigger the QI on IUnknown pointer and return
the IUnknown pointer. **No matter the class is public or not, CLR will
always provide the IUnknown implementation of the object as its CCW. **

Hope this helps.

Regards,
Jie Wang

Microsoft Online Community Support

Delighting our customers is our #1 priority. We welcome your comments and
suggestions about how we can improve the support we provide to you. Please
feel free to let my manager know what you think of the level of service
provided. You can send feedback directly to my manager at:
(e-mail address removed).

==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/en-us/subscriptions/aa948868.aspx#notifications.

Note: MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 2 business days is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions. Issues of this
nature are best handled working with a dedicated Microsoft Support Engineer
by contacting Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/en-us/subscriptions/aa948874.aspx
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
Hi,
Marshal.GetIDispatchForObject QI (QueryInterface) IDispatch on the CCW
(ComCallableWrapper) of the object. Since MyClass is attributed to
ClassInterfaceType.None, it does not have the IDispatch implementation by
CLR, which further fails the QI. QI is the cast operation used in COM. It
makes sense to map the error to InvalidCastOperation.

Similarly, Marshal.GetIUnknown trigger the QI on IUnknown pointer and return
the IUnknown pointer. **No matter the class is public or not, CLR will
always provide the IUnknown implementation of the object as its CCW. **

Thank you very much, now I understand the differences.

Marvin
 
Back
Top