GOTCHA 72 All but one of the ClassInterface options are ineffective


GOTCHA #72 All but one of the ClassInterface options are ineffective

COM clients interact with a component through its supported interfaces. There are three ways to expose a .NET class for COM interoperability. The options are specified through the ClassInterfaceType enumeration's values of AutoDispatch, AutoDual, and None. What is the consequence of choosing one option over another? Understand this to avoid some common mistakes in enabling COM interoperability for your .NET classes. In this gotcha I will discuss each of these approaches. First, consider using AutoDispatch, as shown in Example 8-12 (which is the same as Example 8-11 but has different lines highlighted).

Example 8-12. Exposing .NET component using AutoDispatch

C# (ClassInterfaceType)

 using System; using System.Runtime.InteropServices; namespace ALib {     [Guid("53DEF193-D7A4-4ce3-938E-A7A35B5F7AB7"),         ClassInterface(ClassInterfaceType.AutoDispatch)]     public class MyComponent     {         public void Method1()         {             //...         }     } } 

VB.NET (ClassInterfaceType)

 Imports System.Runtime.InteropServices <Guid("53DEF193-D7A4-4ce3-938E-A7A35B5F7AB7"), _   ClassInterface(ClassInterfaceType.AutoDispatch)> _ Public Class MyComponent     Public Sub Method1()         '...     End Sub End Class 

In this case, you have set the ClassInterface attribute on the class to ClassInterfaceType.AutoDispatch, which is the default value for that attribute. What is the consequence of this setting? What's exposed for the client is affected by this setting and is shown in Figure 8-15.

Figure 8-15. Effect of ClassInterfaceType.AutoDispatch


The class implements only the IDispatch interface. The methods of the class are not exposed directly, so the only way for a client to access this component is using automation. While this is great for scripting clients and VB6 using automation, it is not desirable from the point of view of C++ clients and VB6 in early binding mode.

In the second approach, let's modify the code to use AutoDual as in Example 8-13. The change from AutoDispatch to AutoDual results in a change to what the client sees, as shown in Figure 8-16.

Example 8-13. Exposing .NET component using AutoDual

C# (ClassInterfaceType)

 using System; using System.Runtime.InteropServices; namespace ALib {     [Guid("53DEF193-D7A4-4ce3-938E-A7A35B5F7AB7"),         ClassInterface(ClassInterfaceType.AutoDual)]     public class MyComponent     {         public void Method1()         {             //...         }     } } 

VB.NET (ClassInterfaceType)

 Imports System.Runtime.InteropServices <Guid("53DEF193-D7A4-4ce3-938E-A7A35B5F7AB7"), _   ClassInterface(ClassInterfaceType.AutoDual)> _ Public Class MyComponent     Public Sub Method1()         '...     End Sub End Class 

There is good news and bad news. The good news is that you are exposing Method1() of the component for clients to use. This means that strongly typed languages such as C++ can use your component easily. However, in addition to Method1(), methods of the Object base class are exposed. Second, remember that in COM, interfaces are immutable. Unfortunately, if you add methods, or just move them around, the interface generated will be different. This violates interface immutability, and forces client applications to be recompiled.

A third approach, and the most effective one, is to have the class expose no COM interface at all. Rather, it exposes .NET interfaces separately to COM clients. This is shown in Example 8-14.

Figure 8-16. Effect of ClassInterfaceType.AutoDual


Example 8-14. The only option that works

C# (ClassInterfaceType)

 using System; using System.Runtime.InteropServices; namespace ALib {     [Guid("74555C62-75CD-4c87-940A-4AE8A69FFCB2"),         InterfaceType(ComInterfaceType.InterfaceIsDual)]     public interface IMy     {         void Method1();     }     [Guid("53DEF193-D7A4-4ce3-938E-A7A35B5F7AB7"),         ClassInterface(ClassInterfaceType.None)]     public class MyComponent : IMy     {         public void Method1()         {             //...         }     } } 

VB.NET (ClassInterfaceType)

 Imports System.Runtime.InteropServices <Guid("74555C62-75CD-4c87-940A-4AE8A69FFCB2"), _   InterfaceType(ComInterfaceType.InterfaceIsDual)> _ Public Interface IMy     Sub Method1() End Interface <Guid("53DEF193-D7A4-4ce3-938E-A7A35B5F7AB7"), _   ClassInterface(ClassInterfaceType.None)> _ Public Class MyComponent     Implements IMy     Public Sub Method1() Implements IMy.Method1     End Sub End Class 

In this example, you have an interface IMy with Method1() that you intend to expose to the client. For the IMy interface you have declared its InterfaceType attribute as ComInterfaceType.InterfaceIsDual. This makes the methods of the interface available for both scripting and strongly typed clients. The class MyComponent implements that interface. Furthermore, you have declared its ClassInterface attribute as ClassInterfaceType.None. The types exposed to a COM client are shown in Figure 8-17.

Figure 8-17. Effect of ClassInterfaceType.None


The use of ClassInterfaceType.None brings a .NET component back to how a real COM component should behaveit supports interfaces and does not expose anything to the client on its own. While there are three options to expose a .NET class for COM interoperability, only this last one is meaningful to use.

IN A NUTSHELL

Set the ClassInterface attribute to ClassInterfaceType.None on .NET components you want to expose for COM interoperability; do not use the default. Expose the desired methods to the COM clients through a .NET interface by setting its InterfaceType attribute to ComInterfaceType.InterfaceIsDual.

SEE ALSO

Gotcha #71, "Auto-generating GUID for your classes leads to versioning woes" and Gotcha #73, "Simply tur ning the switch for COM interop is dangerous."



    .NET Gotachas
    .NET Gotachas
    ISBN: N/A
    EAN: N/A
    Year: 2005
    Pages: 126

    flylib.com © 2008-2017.
    If you may any questions please contact us: flylib@qtcs.net