Feb. 3, 2011, 7:03 a.m.
posted by bert
Retrofitting a Class to Interoperate with COMproblemAn existing C# class needs to be usable by a COM object or will need to be usable sometime in the future. You need to make your class work seamlessly with COM. SolutionMicrosoft has made COM interop quite easy. In fact, you really have to complete only two minor steps to make your code visible to COM: By default, this tool will make many decisions for you. For example, new GUIDs are created for your classes and interfaces unless you specify a particular GUID to use. This can be a bad thing; it is usually a good idea to explicitly specify which GUIDs your classes and interfaces are to use. To take control of how your C# code is viewed and used from a COM client, you need to use a few attributes. Figure contains a list of attributes and their descriptions that can be used to control these things. These attributes are used in conjunction with the previous two steps mentioned to create and register the assembly's classes. Several other COM interop attributes exist in the FCL, but the ones mentioned here provide the most basic control over how your assembly is viewed and used by COM clients. DiscussionThe Foo class, defined within the Chapter_Code namespace, shows how these attributes are applied:
using System;
namespace Chapter_Code
{
public class Foo
{
public Foo( ) {}
private int state = 100;
public string PrintMe( )
{
return("TEST SUCCESS");
}
public int ShowState( )
{
return (state);
}
public void SetState(int newState)
{
state = newState;
}
}
}
To allow the Foo type to be exposed to a COM client, you would first add an interface, IFoo, describing the members of Foo that are to be exposed. Adding an interface in this manner is optional, especially if you are exposing classes to scripting clients. However, it is recommended since COM is interface-based and you will be able to explicitly control how it is exported. If the AutoDual interface type is used with the ClassInterfaceAttribute, early-bound clients will not need this interface either. Even though it is optional, it is still a good idea to use an interface in this manner. Next, an unchanging GUID is added to the IFoo interface and the Foo class using the GuidAttribute. The assembly.cs file contains a Guid attribute attached to the assembly with a new GUID. A ProgId is also added to the Foo class. Finally, the class interface type is defined as an AutoDispatch interface, using the ClassInterfaceAttribute. The new code is shown here with the changes highlighted:
using System;
using System.Runtime.InteropServices;
namespace Chapter_Code
{
[GuidAttribute("1C6CD700-A37B-4295-9CC9-D7392FDD425D")]
public interface IFoo
{
string PrintMe( );
int ShowState( );
void SetState(int newState);
}
[GuidAttribute("C09E2DD6-03EE-4fef-BB84-05D3422DD3D9")]
[ClassInterfaceAttribute(ClassInterfaceType.AutoDispatch)]
[ProgIdAttribute("Chapter_Code.Foo")]
public class Foo : IFoo
{
public Foo( ) {}
private int state = 100;
public string PrintMe( )
{
return("TEST SUCCESS");
}
public int ShowState( )
{
return (state);
}
public void SetState(int newState)
{
state = newState;
}
}
}
The code to use the exposed C# code from VB6 code using COM interop is shown here:
Sub TestCOMInterop( )
'ClassLibrary1 was created using Regasm in the Solution section
'of this recipe
Dim x As New ClassLibrary1.Foo
MsgBox ("Current State: " & x.ShowState( ))
x.SetState (-1)
MsgBox ("Current State: " & x.ShowState( ))
MsgBox ("Print String: " & x.PrintMe( ))
End Sub
The first Dim statement creates a new instance of the Foo type that is usable from the VB6 code. The rest of the VB6 code exercises the exposed members of the Foo type. There are some things to keep in mind when exposing C# types to COM clients:
See AlsoSee the "Assembly Registration Tool (Regasm.exe)," "Type Library Exporter (Tlbexp.exe)," "Type Library Importer (Tlbimp.exe)," and "Assembly to Type Library Conversion Summary" topics in the MSDN documentation. |
- Comment
Rebuild Solution or Build