Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

C# ПІДРУЧНИКИ / c# / MS Press - Msdn Training Programming Net Framework With C#

.pdf
Скачиваний:
194
Добавлен:
12.02.2016
Размер:
16.87 Mб
Скачать

Module 15 (Optional): Interoperating Between Managed and Unmanaged Code

45

 

 

 

You can customize the COM callable wrapper by applying interop-specific attributes to your managed source code and compiling the source code into an assembly.

Caution If you plan to export a managed object, be aware that the COM client determines the apartment of the object. A managed object called by a COM client initialized in an MTA must ensure thread safety.

46

Module 15 (Optional): Interoperating Between Managed and Unmanaged Code

Demonstration: Using the Type Library Exporter

Topic Objective

To describe the use of the Type Library Exporter.

Lead-in

The Type Library Exporter is a command-line tool that exports the type information to a type library so that it can be used from a COM client.

*****************************ILLEGAL FOR NON-TRAINER USE******************************

The Type Library Exporter (Tlbexp.exe ) is a command-line tool that builds a type library for .NET Framework classes so that they can be used from unmanaged clients. The Type Library Exporter uses the metadata that is stored in the assembly to generate the type library. The type library contains definitions of the types defined in an assembly. Applications that use unmanaged code can use the generated type library to bind to the .NET Framework types defined in the assembly.

Note You cannot use the Type Library Exporter to produce a type library from an assembly that was imported by using the Type Library Importer (Tlbimp.exe). Instead, you should refer to the original type library that was imported with the Type Library Importer. You can export a type library from an assembly that references assemblies that were imported by using the Type Library Importer.

You must use the Type Library Exporter to generate a type library for an entire assembly and not just a subset of the types that are defined in the assembly. A single assembly may cause several type libraries to be generated, and these type library files are placed in the current working directory or the directory specified for the output file when running the Type Library Exporter.

The Type Library Exporter generates a type library but does not register the types it exports with the system registry. To generate and register a type library with COM, use the Assembly Registration tool (Regasm.exe). For information about using the Assembly Registration tool to register a type library, see Registering a .NET Framework class with the System Registry in this module.

Module 15 (Optional): Interoperating Between Managed and Unmanaged Code

47

 

 

 

The Export Process

Topic Objective

To describe how the export process converts classes and interfaces.

Lead-in

The export process creates definitions for the classes and interfaces that are defined in an assembly.

!Every public class in an assembly is converted to a coclass in a type library

!Interfaces that are explicitly implemented are exported to the type library

Managed Code

public interface IShape public interface IShape

{{

void Draw(); void Draw();

}}

void Move(int x, int y); void Move(int x, int y);

class Circle : IShape class Circle : IShape

{{

void Draw(); void Draw();

}}

void Move(int x, int y); void Move(int x, int y); void Enlarge(int x); void Enlarge(int x);

Type Library

[ uuid(…), dual, odl, oleautomation ] [ uuid(…), dual, odl, oleautomation ] interface IShape : IDispatch { interface IShape : IDispatch {

HRESULT Draw();

HRESULT Draw();

}}

HRESULT Move(int x, int y);

HRESULT Move(int x, int y);

[ uuid(…) ] [ uuid(…) ]

coclass Circle { coclass Circle {

}}

interface IShape; interface IShape;

}}

*****************************ILLEGAL FOR NON-TRAINER USE******************************

When you run the Type Library Exporter on your assembly to generate a type library, the export process converts the classes and interfaces defined in your assembly, and creates representations for them in the type library.

The export process converts each public class in an assembly to a coclass in a type library, and gives the coclass the same name as the managed class. All the interfaces that are explicitly implemented by the managed class are exported to the type library. Methods and properties are not exported.

When the class in the example in the slide is exported, the type library will contain a representation for the IShape interface and a coclass definition for the Circle class. The Draw, Move, and Enlarge methods of the Circle class will not be exported.

When an assembly is exported, all managed interfaces and their methods and properties are converted to COM interfaces. By default, the COM interface that is generated in the type library file is a dual interface. You can use the ClassInterfaceAttribute to determine the type of interface that is defined when the type library is exported.

Each coclass can implement one other interface, called the class interface, which the export process generates automatically. The class interface exposes all methods and properties available in the original managed class, thereby enabling COM clients to access them by calling through the class interface.

48

Module 15 (Optional): Interoperating Between Managed and Unmanaged Code

Registering a .NET Framework Class with the System Registry

Topic Objective

To describe the procedure for registering a .NET Framework class with the system registry.

Lead-in

Before you can use a .NET Framework class from unmanaged code, you must register the class with the system registry.

!To register a .NET Framework class with the system registry, use the Assembly Registration tool (Regasm.exe)

!Registering a .NET Framework class creates the following entries in the system registry:

#The CLSID of the .NET Framework class under the Hkey_Classes_Root\CLSID registry key

#Two sub keys: Implemented Categories and InprocServer32 under the HKCR\CLSID\<class ID> key

!The default value of the HKCR\CLSID\<class ID> key is set to the ProgID of the class

!The default value of the InprocServer32 is set to the name of the DLL that contains the common language runtime (Mscoree.dll)

*****************************ILLEGAL FOR NON-TRAINER USE******************************

Before you can use a .NET Framework class from unmanaged code, you must register the class with the system registry. To register a .NET Framework class with the system registry, you use the command-line Assembly Registration tool (Regasm.exe). The Assembly Registration tool adds information about the class to the system registry so COM clients can use the .NET Framework class transparently. You can also use the RegistrationServices class from within your managed code, to register your .NET Framework class with the system registry.

When you register a .NET Framework class, the following entries are made in the system registry:

!A new entry for the class identifier (CLSID) of the .NET Framework class is created under the HKEY_CLASSES_ROOT\CLSID registry key. After the CLSID is generated for the .NET Framework class, the Assembly Registration tool always uses the same CLSID, regardless of the number of times it is used on the class.

!Under the HKEY_CLASSES_ROOT\CLSID\<class ID> key, are two sub keys: ImplementedCategories and InprocServer32. The default value of the HKEY_CLASSES_ROOT\CLSID\<class ID> key is set to the

ProgID of the class. The default value of the InprocServer32 is set to the name of the DLL that contains the common language runtime (Mscoree.dll).

When a COM client attempts to load the assembly in which the class is implemented, the runtime reads the assembly value from the registry and passes it on to the runtime assembly resolver. The assembly resolver attempts to locate the assembly based on the assembly information, such as the name and version number. Before the assembly resolver can locate the assembly, however, the assembly must be signed and installed in the global assembly cache, or it must be in the application’s root directory or a subdirectory of the application’s root directory.

Module 15 (Optional): Interoperating Between Managed and Unmanaged Code

49

 

 

 

Using the ClassInterfaceAttribute

Topic Objective

To describe the use of the

ClassInterfaceAttribute to control the type of interface that is created for a managed class.

Lead-in

When used with a .NET Framework class, the

ClassInterfaceAttribute can be used to control and modify the type of interface that is generated when that

.NET Framework class is exported.

!The class interface is an interface that exposes all public methods, properties, fields, and events that are explicitly exposed on the .NET Framework object

!The [ClassInterface(ClassInterfaceType.None)] attribute prevents the class interface from being created

!The [ClassInterface(ClassInterfaceType.AutoDispatch)] attribute creates a dispatch interface

!The [ClassInterface(ClassInterfaceType.AutoDual)] attribute creates a dual interface

*****************************ILLEGAL FOR NON-TRAINER USE******************************

The class interface is an interface that exposes all public methods, properties, fields, and events that are explicitly exposed on a .NET Framework object. This interface can be a dual or dispatch-only interface. The class interface receives the name of the .NET Framework class, preceded by an underscore.

When you use the Type Library Exporter to generate a type library for a managed class, a dispatch-only interface for each class you export is created by default. You can use the ClassInterfaceAttribute with your class to prevent or modify the automatic creation of this interface. When you use the

ClassInterfaceAttribute, you must add the Sytem.Runtime.InteropServices namespace to your code.

You use the ClassInterfaceAttribute and pass the value ClassInterfaceType.None to the constructor, to prevent the class interface from being generated when the class metadata is exported to a type library, as shown in the following example:

[ClassInterface(ClassInterfaceType.None)] public class LoanApp : IExplicit

{

void M();

}

In the preceding example, COM clients can access the LoanApp class only through the IExplicit interface.

50

Module 15 (Optional): Interoperating Between Managed and Unmanaged Code

To avoid breaking late-bound COM clients when using the class interface, set the Value property of the ClassInterfaceAttribute to

ClassInterfaceType.AutoDispatch. This value implements a dispatch-only class interface, but omits the interface description from the type library. Without an interface description, clients are unable to cache dispatch identifiers (DISPIDs) at compile time. Although this is the default interface type for the class interface, you can apply the attribute value explicitly, as shown in the following example:

[ClassInterface(ClassInterfaceType.AutoDispatch)] public class LoanApp : IAnother

{

void M();

}

To get the DISPID of an interface member at run time, COM clients can call IDispatch.GetIdsOfNames. To invoke a method on the interface, pass the returned DISPID as an argument to IDispatch.Invoke.

A dual interface that is automatically generated (ClassInterface.AutoDual) might be appropriate in rare cases. However, a dual interface that is automatically generated often creates version-related complexities. For example, COM clients that are using the class interface of a derived class can easily break when there are changes to the base class. When a third party provides the base class, the layout of the class interface is out of your control. Further, unlike a dispatch-only interface, a dual interface provides a description of the class interface in the exported type library. Such a description encourages late-bound clients to cache DISPIDs at run time.

Module 15 (Optional): Interoperating Between Managed and Unmanaged Code

51

 

 

 

Using .NET Framework Types from COM

Topic Objective

To describe the procedure for using .NET Framework types from COM clients.

Lead-in

After you have generated a type library for your .NET assembly, you can use the assembly from unmanaged code.

!To Use a .NET Framework Class from Unmanaged Code

#Set a reference to the type library file that describes the interferences of the .NET Framework class

!In Visual Basic 6.0, Use the References Dialog Box to Set the Reference

!In Visual C++ 6.0, Use the #import Directive to Reference to the Type Library

!Create and Use Objects of the Classes That Are Defined in the Type Library

*****************************ILLEGAL FOR NON-TRAINER USE******************************

After you have exported the metadata from an assembly to a type library file, you can use the .NET Framework classes that are implemented in the assembly as you would create and use a COM object.

!To use a .NET Framework class that has been exported to a type library from a Visual Basic 6.0 application

1.In Visual Studio 6.0, on the Project menu, click References. The References dialog box appears.

2.To add the reference to your project, scroll down Available References list, click the reference you want to add, and then click OK.

3.Create an object of the .NET Framework class (as you would create a COM object), as shown in the following example:

Dim Server As New ExcelServer.ExcelServer

4.Use the methods and properties of the class, as shown in the following example:

Dim Count As Integer

Count = Server.Count

To use a .NET Framework class from a Microsoft Visual C++® 6.0 application, use the #import directive to reference the type library, as shown in the following example:

#import "c:\Samples\SampleClassLibrary\SampleClassLib.tlb"

52

Module 15 (Optional): Interoperating Between Managed and Unmanaged Code

Managed and Unmanaged Events

Topic Objective

To understand at a high level interoperability between .NET and COM events

Lead-in

Let’s look at how the NET Framework event model differs from the traditional COM event model.

!.NET event model differs from COM event model

#Managed events are based on delegates, whereas unmanaged events (in COM) are based on connection points.

!See the .NET SDK for details on the topics:

#Handling Events Raised by a COM Source

#Raising Events Handled by a COM Sink

*****************************ILLEGAL FOR NON-TRAINER USE******************************

The .NET Framework event model differs from the traditional COM event model. Managed events are based on delegates, whereas unmanaged events in COM are based on connection points. Both models are tightly coupled event systems, because the client (event receiver) and server (event sender) must run simultaneously.

The SDK explains in detail how to bridge the managed and unmanaged event systems, enabling objects to send and receive events across the interoperation boundary. Topics include Handling Events Raised by a COM Source and Raising Events Handled by a COM Sink.

Module 15 (Optional): Interoperating Between Managed and Unmanaged Code

53

 

 

 

Best Practices

Topic Objective

To list some best practices when using managed classes from COM clients.

Lead-in

When exposing managed code to COM clients, follow the best practices listed on the slide.

!Define an Explicit Interface for COM Clients to Use Rather Than Generating the Class Interface

!Avoid Caching Dispatch Identifiers

!Restrict Using the Dual Interface Option for the Class Interface

*****************************ILLEGAL FOR NON-TRAINER USE******************************

When exposing managed code to COM clients, use the following best practices:

!Define an explicit interface for COM clients to use rather than generating the class interface.

Because COM interop services generate class interfaces automatically, postversion changes to your class can alter the layout of the class interface exposed by the common language runtime. Since COM clients are typically unprepared to handle changes in the layout of an interface, they break if you change the member layout of the class.

To reduce the risk of breaking COM clients by inadvertently reordering the interface layout, isolate all changes to the class from the interface layout by explicitly defining interfaces.

Set the Value property of ClassInterfaceAttribute to

ClassInterfaceType.None to disengage the automatic generation of the class interface and implement an explicit interface for the class.

!Avoid caching dispatch identifiers (DISPIDs).

Using the class interface is an acceptable option for scripted clients, Visual Basic 6.0 clients, or any late-bound client that does not cache the DISPIDs of interface members. DISPIDs identify interface members and enable late binding.

For the class interface, generation of DISPIDs is based on the position of the member in the interface. If you change the order of the member and export the class to a type library, you will alter the DISPIDs generated in the class interface.

54

Module 15 (Optional): Interoperating Between Managed and Unmanaged Code

To avoid breaking late-bound COM clients when using the class interface, set the Value property of the ClassInterfaceAttribute to

ClassInterfaceType.AutoDispatch. This value implements a dispatch-only class interface, but it omits the interface description from the type library. Without an interface description, clients are unable to cache DISPIDs at compile time. Although this is the default interface type for the class interface, you can apply the attribute value explicitly.

!Restrict using the dual interface option for the class interface.

Dual interfaces enable early and late binding to interface members by COM clients. At design time and during testing, you might find it useful to set the class interface to dual. For a managed class and its base classes that will never be modified, this option is also acceptable. In all other cases, avoid setting the class interface to dual.

Соседние файлы в папке c#