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

Microsoft Visual C++ .NET Professional Projects - Premier Press

.pdf
Скачиваний:
180
Добавлен:
24.05.2014
Размер:
26 Мб
Скачать
☆

This page intentionally left blank

 

 

Y

 

L

 

F

 

M

 

A

 

E

 

T

 

 

Team-Fly®

Project 8

.NET Assemblies with Managed C++ and

.NET Interoperability with COM

Project 8 Overview

In Part VI of this book, you learned how COM components help in code reuse and in encapsulating the business logic for the n-tier application. While COM components are very popular and widely used, they do have a few shortcomings. In the .NET Framework, Microsoft has tried to address these shortcomings.

On the .NET platform, components will be created as assemblies. .NET introduces a new unit of code reuse, an assembly. An assembly is a self-con- tained unit consisting not only of the code required for its logic implementation, but also the metadata that describes the assembly itself. But what will happen to the huge investments companies have made in COM-based components and software? .NET provides a way for this code base to be put to use by providing the interop services that enable interoperability between COM and .NET components.

In this project, you will learn how an existing COM component can be used in a .NET application. Also, you will explore how a .NET component can be used by a legacy (COM-based) application. You have already learned about the role of COM+ services in providing the required plumbing for creating enterprise applications on the Windows platform. You will explore, in this project, how the classes under the System::EnterpriseServices namespace of the .NET Framework make the COM+ services available to .NET components.

Chapter 25

Overview of Assemblies, Manifests in .NET, and Interoperability with COM

As discussed in Chapter 17, components were introduced to make code reusability a reality and to ease the maintenance of applications. Over the years, the component technology has evolved, but the reason for its use still remains the same. A component is nothing but a piece of reusable code. Initially code reusability was achieved using static libraries and dynamically linked libraries. With Windows NT, Microsoft introduced COM, an architecture that allowed language independent code reuse. COM components can be created as a

DLL or as an executable file.

.NET introduces the concept of assemblies. .NET components are housed in assemblies. An assembly is a structure containing the reusable component and metadata describing it. Does this mean that COM and related concepts are extinct? No, definitely not. Just as when a new version of existing software is released, the new version has backward compatibility with the older versions,

.NET components are compatible with the earlier COM-based technologies. In turn, you can use the existing COM components in .NET assemblies.

This chapter introduces you to the role played by assemblies in .NET and discusses the basics of assemblies. This chapter also throws light on how the interoperability happens between COM components and .NET assemblies.

Assemblies

Assemblies are strongly placed in .NET because they are elementary units in any

.NET application. They play a pivotal role in versioning, deployment, and reuse in all .NET applications. In simple words, an assembly is a set of resources and types, built together to form a logical unit of functionality.

The most significant feature of an assembly is that it is self-describing, implying that it furnishes all information required to access it. All of this information is available in a manifest. A manifest is a data structure that stores all details about the assembly within which it resides. Some of the information stored in a manifest includes an assembly’s identity, names of all constituent files, details of the types included in the assembly, and other permissions-related information.

OVERVIEW OF ASSEMBLIES, MANIFESTS IN .NET

Chapter 25

755

 

 

 

 

NOTE

One of the significant roles of assemblies is to supply information to the CLR. This information (which is stored in the manifest) provides details about type implementations to CLR; hence, CLR recognizes the existence of a type only in the context of an assembly.

Types of Assemblies

Assemblies are classified into the following two categories based on their execution:

Static assemblies. Include .NET Framework resources, such as bitmaps, and types, such as classes. Static assemblies need to be stored as PE (portable executable) files, which are disk files.

Dynamic assemblies. Unlike static assemblies, dynamic assemblies can be executed directly from within memory, and therefore need not be saved on a disk file.

As stated earlier, an assembly holds a key role in .NET programming. An assembly:

Structures a type boundary. A type’s name and identity is determined by the name of the assembly that contains the type.

Structures a security boundary. An assembly thereby acts as a unit from which permissions are requested and granted.

Structures a version boundary. All resources and types in an assembly are versioned as a single unit.

Structures a deployment unit. To simplify the downloading of your application, you need to ensure that only those assemblies that the application calls initially are available when the application is started. Further, the application should be able to retrieve other assemblies when required.

NOTE

An assembly can have only one of the following entry points: a Main, WinMain, or DllMain functions.

756 Project 8 .NET ASSEMBLIES WITH MANAGED C++ AND .NET

Contains code that the CLR executes. When such an assembly is reusable, it is packaged as static assemblies. If an assembly doesn’t have an associated manifest, it is called a module. However, you can use the linker to link a module with an existing assembly.

Assemblies, besides being classified based on their execution types, can also be classified based on the types of applications that can access them. This categorization includes two types: private assemblies and shared assemblies.

Private Assemblies

A private assembly is created as the default assembly while compiling a program. This implies that the assembly can be used by only one application and is not available to other applications that don’t reside in the assembly folder. On the Windows file system, the files that constitute the assembly are located either in the same folder as the application or in one of its subfolders.

The main advantage of using private assemblies is that it simplifies the naming requirements of assemblies. Since a private assembly is not available to other applications located on the file system, the only thing you need to ensure when naming your assembly is that the name is unique within your application. Further, it is not necessary to have unique names for all assemblies within a file system to avoid name clashes. In addition, a private assembly rules out the possibility of interference of other software with your assembly.

The fact that a private assembly is not available to other applications located on the file system has some other implications. If multiple software packages are using the same private assembly, then the assembly is provided at the location of each package and installed with each folder or subfolder. This might not be a favorable solution always. The workaround is to make the assembly a shared assembly.

Shared Assemblies

Although shared assemblies enable other software to use your assembly, you might face problems while naming shared assemblies, because if you want to share an assembly across a file system, the name of the assembly must be unique across the entire file system.

Another situation where you need to be careful is while installing and using newer versions of the supplied component. You need to considerthe potential harm that

OVERVIEW OF ASSEMBLIES, MANIFESTS IN .NET

Chapter 25

757

 

 

 

 

the installation can do to existing applications. To avoid this problem, a unique shared name can be given to a shared assembly and then install the assembly in the global assembly cache, an area of the file system in the folder WinNT\Assembly. This folder contains shared assemblies.

You cannot make a private assembly into a shared assembly at run time, but you can do so after compilation. There are numerous utilities provided by Microsoft to convert a private assembly into a shared assembly. These utilities ensure that the conversion of a private assembly into a shared assembly is a deliberate decision of the developer. The command-line utility assembly linker (Al.exe) is one such utility. This utility generates a file with an assembly manifest by using resource or module files.

The syntax of using the assembly linker utility is as follows:

al sources options

In the preceding syntax, sources can be specified as one of the following:

/link[resource]:file[,name[,target[,private]]]. This source creates a link between an assembly and the resource file. In this case, rather than copying the file, the utility converts the resource specified by file into a part of the assembly.

/embed[resource]:file[,name[, private]]. This source sets the resource specified by file in the image containing the assembly manifest. The utility copies the contents of file into the portable executable image.

file[,target]. This source ensures that the contents of file are copied into the file name specified by target. The utility then compiles the target into an assembly.

In the next section, you will understand the role of the global assembly cache in creating a shared assembly.

Global Assembly Cache

The global assembly cache is an area of the file system in the folder WinNT\Assembly that stores assemblies that are shared by multiple applications on a computer.

758 Project 8 .NET ASSEMBLIES WITH MANAGED C++ AND .NET

NOTE

Every computer that has the .NET Framework installed has the global assembly cache.

You can deploy an assembly by using any one of the following methods:

By using the .NET Framework Configuration tool. This tool is provided by the .NET Framework SDK.

By using an installer that works with the global assembly cache.

By using the GacUtil.exe utility, which is the preferred method. You will learn how to use gacutil.exe later in the section Converting a Private

Assembly into a Shared Assembly.

Benefits of Assemblies

Initially code sharing happened through the use of static libraries. Frequently used methods and classes were compiled into a static library. When the executable for an application using these methods or classes was created, the static library was appended to the executable. The next innovation in this direction was the use of dynamically linked libraries (DLLs). Similar to static libraries, DLLs contain code that is reusable. The reusable code is placed in a file with an extension DLL and is different from a static library in that the reusable code is separated from the executable file. The code in the DLL is loaded into the memory when required by the executable. The use of DLLs proved to be quite useful because DLLs could be linked at run time and shared between multiple applications that were running simultaneously, and this meant saving a significant amount of memory space.

The advent of COM gave a new dimension to code reusability, because COM was language independent. You can call a COM component from any COM-aware language, irrespective of the language in which the component was written. In addition, you could call COM components across processes and computers. The use of COM also enabled you to view the components available on a computer, because of the manner in which the components were registered in the registry.

However, using COM components has certain disadvantage:

Information about each component needs to be stored in multiple locations. The code is located in the DLL in which a component is hosted

OVERVIEW OF ASSEMBLIES, MANIFESTS IN .NET

Chapter 25

759

 

 

 

 

and the references are stored in the registry. Dispersing information in such a manner makes it difficult to coordinate it.

You store information in the registry to view the information about the software on a computer. However, this complicates the software installation process.

In cases where a particular COM component is to be made available across the network, registry entries need to be created on every computer on the network that can call the component.

Even if you want a registered component to be used by only one application, the component is made available to all the applications on the computer. This leads to the registry getting distended with useless information.

Besides these problems, there might be situations in which an application stops working due to compatibility issues between different versions of a DLL. This problem, popularly called DLL Hell, affects DLLs as well as COM components. Such a situation is very difficult to avoid because considerable efforts are aimed at improving components by adding new functions, extending classes, and fixing existing bugs. Thus, it is not possible to avoid newer versions of a DLL.

Theoretically speaking, you can avoid DLL Hell by following this guideline: Whenever you improve a component, ensure that the component is compatible with its older versions. However, when the focus is on improving a technology, it is sometimes impossible to ensure backward compatibility. Thus, the risk is high that whenever you install software containing the latest version of a shared DLL, applications using the shared DLL might stop working.

Assemblies take care of most of the problems that arise with the use of DLLs and COM components. The concept of private and shared assemblies, discussed earlier, solves the problem of registration of COM components. Assembly versioning, discussed next, solves the problem of DLL Hell.

Assembly Versioning

Assembly versioning addresses the problem of DLL Hell. The identity of an assembly is defined by its name as well as its version. This makes it possible for the assembly cache to hold multiple versions of an assembly. But remember that assemblies do not ensure that a newer version of a DLL is compatible with an older one. A client call to an assembly always specifies the version that the client