How to Design .NET Components for Use with COM

team lib

How to Design .NET Components for Use with COM

If you are writing a .NET component that you know will be used by COM clients , you can take certain steps to make interoperation as smooth as possible.

Provide a Default Constructor

COM objects are created without any initialization parameters being passed to them; in effect, COM coclasses only ever have default constructors. Any .NET type you expose to COM must therefore have a default constructor. If you also want to provide constructors with parameters for use by .NET clients, youll need to make sure you provide the same functionality to COM clients by supplying a default constructor plus one or more initialization methods .

Avoid Using Static and Overloaded Methods

Static methods arent exported to COM type libraries, so you should avoid using them because they wont be COM-visible. Note that you can see static methods using the .NET reflection mechanism, but this requires you to know .NET programming. Programming .NET reflection falls outside the scope of this book.

Overloaded methods get exported to COM with unique names identified by a numeric suffix, as was explained in the section Exporting Methods earlier in the chapter. This can be confusing for COM clients because the names of the methods in the type library wont match up with the documented names of the original .NET methods. In addition, changing the .NET class and re-exporting the type library might result in different names being generated, which can break existing clients.

Be Aware of Possible Naming Problems

You can run into problems in several areas with the names you use in .NET assemblies and types. For example, its common sense not to use names that are significant in COM, such as IUnknown or BSTR .

In addition, dont differentiate members of types based solely on case. Type libraries arent case sensitive, so the differences between members differentiated in this way can be lost or give rise to apparently overloaded methods.

Assembly Naming

When type libraries are imported into Visual Basic 6 or unmanaged Visual C++ code, the tools might create a namespace based on the library name found in the type library. Because the library name is created from the assembly name during the export process, you should choose an assembly name that gives rise to a sensible library name.

If youre using Visual Studio .NET, you can set the assembly name from the solution property dialog. The name of the output file will be based on the assembly name, so choosing an assembly name of MyProject.MyComponent will result in the creation of an assembly called MyProject.MyComponent.dll . Since type library names cannot contain periods, the generated library name will be MyProject_MyComponent . You might want to avoid the use of long, descriptive assembly names for assemblies that are going to be exported to COM, to make it easier for clients to use the resulting type library.

Method-Naming Conflicts

Be careful not to define methods that have the same names as those in the IUnknown or IDispatch interface. In other words, avoid using the following names:

  • QueryInterface

  • AddRef

  • Release

  • GetTypeInfoCount

  • GetTypeInfo

  • GetIdsOfNames

  • Invoke

If you define a method name that clashes with one of these, the type library exporter will deal with it in the usual way, by creating a COM interface method with a numeric suffix (for example, GetTypeInfo_2 ).

Avoid Altering Interfaces

A fundamental principle of COM is that once an interface has been defined, it shouldnt be changed in any way that will affect users of the interface. This means not adding methods, not removing methods, not changing method signatures, and not changing the order of the methods within an interface definition.

.NET classes and their clients are more able to cope with change than COM interfaces and clients. You can also change .NET type definitionsfor instance, reordering the methods within a classwithout breaking client code. If youre going to expose a .NET class to COM, you need to ensure you dont make changes to the class that will cause problems to COM clients. Treat the public interface to exported .NET classes as you would COM interfaces, providing a new version number if you make any potentially breaking change.

Note 

COM clients can see only the public members of .NET classes, so you can change private and protected members without compromising COM safety.

Define Event Source Interfaces

If you want your .NET class to fire events that can be handled by COM clients, define event-source interfaces in managed code and attach them to .NET classes using the ComSourceInterfaces attribute. This procedure is discussed in more detail in the Exposing .NET Events in COM section later in the chapter.

Use of Attributes

.NET components use attributes to provide data about types above and beyond what the programming language can convey . For example, to show that a class is serializable, it is tagged with the Serializable attribute:

 [Serializable()] publicclassMyClass { ... } 

You can also create your own custom attributes, which are used in exactly the same way.

Finding out what attributes a class possesses requires writing code that uses reflection; reflection provides a run-time query of an objects capabilities. You can use reflection from COM clients, but this will normally require late binding to the .NET object. Such code is difficult to write and requires knowledge of how the .NET reflection mechanism works.

Other object-oriented languages that dont support attributes use a different technique. An interface with no members can be used to tag a class as having a particular property. For example, in C++ making a class serializable might be implemented like this:

 //Dummyinterface classISerializable { }; classMyClass:publicISerializable { ... }; 

You can use a simple cast at run time to find out whether an object inherits from ISerializable . This might be a better way to expose attributes to COM clients because ISerializable will be exported as an interface and can be discovered by a simple call to QueryInterface . Interface methods can be used to provide the same information that can be obtained from custom attributes by reflection.

Provide HRESULT s

.NET code signals errors by throwing exceptions, and the interop mechanism passes these to COM clients as HRESULT s. Although the .NET coding guidelines recommend that you use the exception classes predefined in the .NET Framework, you can define your own exception types if you need to pass information. If you define your own custom exception classes, youll need to include an HRESULT so that it can be passed to COM. You can include an HRESULT by using the protected HResult property inherited from the Exception base class.

Note 

Youll need to create a suitable value for the HRESULT . All HRESULT s not originating from Microsoft must start with 0x8004 (representing a FACILITY_ITF error), and the last four hex digits must be greater than 0x200.

Use Versioning Correctly

The type library exporter will automatically generate GUIDs for type libraries, coclasses, and interfaces. These GUIDs are based on the assembly name, the version, and the public key; if the assembly doesnt have a public key, the GUID will be based only on the name and the version.

When you develop projects in Visual Studio .NET, whether they are in Visual C#, managed C++, or Visual Basic .NET, they contain an AssemblyInfo source file that contains the definitions of attributes that will be applied to the assembly. One of these is the AssemblyVersion attribute, which appears in C# code like this:

 [assembly:AssemblyVersion("1.0.*")] 

The * in the version number tells Visual Studio .NET to automatically generate the last two parts of the version number. These two parts will change with every rebuild of the assembly. This means that every time the assembly is exported, the generated GUIDs for coclasses, interfaces, and the type library might be different because they are based in part on the version number.

To provide fixed GUIDs for exported COM entities, you have two alternatives. The first is to provide an explicit version number in the AssemblyVersion attribute, and the second is to provide explicit GUIDs for coclasses and interfaces using the .NET Guid attribute.

 
team lib


COM Programming with Microsoft .NET
COM Programming with Microsoft .NET
ISBN: 0735618755
EAN: 2147483647
Year: 2006
Pages: 140

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