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

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

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

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

COM clients that require using it. Though multiple clients hold references to a CCW, the CCW holds a single reference to the managed object.

The CCW is mainly used for marshalling calls between managed and unmanaged code. In addition, the CCW is used to manage the lifetime and identity of the managed objects for which it is created.

COM clients are able to reference wrappers directly because CCWs are not allocated memory by the runtime from the garbage-collected heap. On the other hand, the runtime is able to move around .NET objects in the memory because

.NET objects are allocated memory from the garbage-collected heap. The man-

aged object implements the interface and is garbage-collected. Also note that a

 

 

Y

COM client and a .NET client can place simultaneous requests on a managed

 

L

object. Figure 25-2 illustrates how .NET objects are accessed by using the CCW.

 

F

 

M

 

A

 

E

 

T

 

 

FIGURE 25-2 Using the CCW to access .NET objects

In contrast to the concept of the CCW, which makes .NET components appear as COM components to the COM objects, the runtime generates a Runtime Callable Wrapper, which makes a COM component appear as a .NET component to other .NET objects. This proxy is discussed in the next section.

Team-Fly®

OVERVIEW OF ASSEMBLIES, MANIFESTS IN .NET

Chapter 25

771

 

 

 

 

Runtime Callable Wrapper

.NET provides interoperability features that allow you to work with existing unmanaged code (code running outside the CLR) in COM components as well as Win32 DLLs. The .NET CLR enables interoperability by hiding the complexity associated with calls between managed and unmanaged code. The runtime automatically generates code to translate calls between the two environments.

When you call a COM object from .NET, the runtime generates an RCW. The RCW acts as a surrogate for the unmanaged object. The RCW handles all interaction between the .NET client and the COM component. It takes care of creating and binding the COM object, translating and marshaling data between environments, and managing the lifetime of the wrapped COM object.

As with a CCW, the runtime creates exactly one RCW for each COM object, irrespective of the number of references that exist on that particular COM object. Like the CCW, the RCW also actively marshals data between managed and unmanaged code besides maintaining a cache of interface pointers on the wrapped COM object.

Figure 25-3 illustrates how COM objects are accessed by using the RCW.

FIGURE 25-3 Using the RCW to access COM objects

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

With regard to the release process of an RCW, as already mentioned, an RCW maintains a cache of interface pointers on the COM object that it wraps. The RCW releases its reference on the COM object when it is no longer needed. The runtime performs garbage collection on the RCW according to its garbage-col- lection cycle.

Calling COM Objects from .NET

Developers have been using COM to create reusable code and encapsulate business logic for years. Consequently, a lot of COM components are available for use. What will happen to all of these components when the platform of choice becomes .NET? It would be too tedious to rewrite all of them using a native

.NET language like C# or VB.NET or to migrate them using Visual C++ .NET. So, as previously discussed, Microsoft has provided the interop services, which allow interoperability between .NET and COM.

In this section, you will see how you can access a COM component from a .NET client. To do this, you will use the Credit Card Validation component created in Chapter 19. To access it, you will be creating a .NET client using Managed C++.

The first point to note is that the component cannot be accessed as it is. In order to access the component, the client will require a type library. The type library will be embedded within the component. To make it accessible to the client, you will use the Type Library Importer utility (TlbImp.exe). TlbImp.exe can check a COM component, understand its type library, create a manifest from it, and create a proxy assembly that will house the manifest.

The .NET client will make use of the proxy assembly, RCW, which in turn will call the actual COM component. Remember, the utility does not convert the COM component into a .NET component. It simply creates a proxy, which will call the original component using COM services. In addition, the proxy assembly has to be in the same folder as the client (unless it has been exported to the assembly cache).

First, you will create a key file to create an assembly with a strong name (it’s always a good idea to have a strong name for an assembly), just in case you need to use it from the global assembly cache or with the COM+ Services. You can create a new key file using the following syntax:

sn –k key4.snk

OVERVIEW OF ASSEMBLIES, MANIFESTS IN .NET

Chapter 25

773

 

 

 

 

Once the key file has been created, you can use the TlbImp.exe utility to create the proxy assembly. The syntax is shown in Figure 25-4.

FIGURE 25-4 Using the TlbImp.exe utility

In the command-line syntax shown in Figure 25-4, the /out:LuhnCheckerAssm option specifies the name for the proxy DLL, and the /Keyfile:Key4.snk option specifies the name of the key file to be used. The utility responds by giving a list of classes and interfaces imported, CCheckCard and ICheckCard in this case.

The proxy assembly is ready for use now.

Next, you will create the Managed C++ client to access the component. Start Visual C++ .NET and create a new Visual C++ Project of the type Managed C++ Application. Call the application ManageCppAPP.

You will find the names of the files created by the IDE in the Solution Explorer window. You will find that a file ManageCPPApp.cpp has been created for you. It will have a single main function as shown here:

int _tmain(void)

{

// TODO: Please replace the sample code below with your own. return 0;

}

You need to add all the required code in this file . But, before you alter the code, copy LuhnCheckerAssm.dll (the proxy assembly you previously created) into the project folder.

Once the proxy assembly has been copied, you need to import the DLLs containing the namespaces required:

_tmain

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

#include “stdafx.h”

#using <mscorlib.dll>

#using <system.dll>

#using <System.Windows.Forms.dll>

#include <tchar.h>

#using “LuhnCheckerAssm.dll”

In the preceding code, #using “LuhnCheckerAssm.dll” assumes that the assembly is in the same folder as the CPP file. You will use a message box to display the result of validating a credit card number. For this, you need System.windows.forms.dll.

Include the following namespace declarations:

using namespace LuhnCheckerAssm;

using namespace System;

using namespace System::Windows::Forms;

Next, within the function, you need to create an instance of the CCardCheck class in the LuhnChecker component:

LuhnCheckerAssm::CCardCheckClass *c1=new LuhnCheckerAssm::CCardCheckClass();

Next, set the CardType property to a valid card type, Visa, and call the Validate method with a card number as a parameter and display the results of the validation. The value returned by the method needs to be UnBoxed by using the

ToString method:

c1->CardType=”Visa”;

if(String::CompareOrdinal((c1->Validate(“4111111111111111”))->ToString(),”0”)==0)

MessageBox::Show(“Valid”,”Card Status”);

else

MessageBox::Show(“Invalid”,”Card Status”);

Build the program. When you try to execute the program, you will find that it generates an exception. This happens because the executable you created is in the debug folder, and the proxy assembly is not in that folder. You can solve this problem in either of two ways:

Copy the assembly into the folder containing the executable.

Put the assembly into the global assembly cache.

OVERVIEW OF ASSEMBLIES, MANIFESTS IN .NET

Chapter 25

775

 

 

 

 

Once you put the assembly in the global cache, it becomes accessible to clients running anywhere from the system. For this, use the GacUtil.exe tool as follows:

GacUtil /i LuhnCheckerAssm.dll

This will export the assembly into the global assembly cache, from where it becomes accessible to all applications in the system.

Calling .NET Objects from COM

In the immediate scenario, even though it looks more likely that COM components will be used from the .NET applications, it is possible that sometimes .NET components will be used from COM applications. In the next chapter, you will learn how to create a .NET assembly using Managed C++ Extensions and access it from COM-based clients.

Summary

In this chapter, you have learned about assemblies and their types, private and shared, and about versioning of assemblies. You also learned about the Global Assembly Cache, and how it is used as a repository for all assemblies that will be shared by multiple applications. Besides this, you also learned about COM and

.NET interoperability, the role of CCW and RCW in implementing the interoperability, and how to use COM components from .NET applications and .NET components from COM-based applications.

This page intentionally left blank

Chapter 26

Implementation

of COM and .NET

Interoperability

You have acquired the basic knowledge about COM and COM+ services in Chapter 17. You have also learned that assemblies are the way to create components in .NET. In this chapter, you will create a .NET assembly using Managed C++ extensions, and verify .NET’s interoperability with COM by accessing this assembly from COM-based clients. Before getting into programming the assembly, I will first introduce the scenario for which you will design the project. Then, I will take you through the tasks performed in different phases of the project life cycle and discuss the design of the project. After discussing the design, I

will take you through the steps required to create the project.

Art-Shop – Creating a Login Component

From the previous chapters, you know that the Art-Shop online art gallery is being developed by Code-Forge. Now the site is online and is generating a fair amount of business. The promoters of Art-Shop have plans to keep their marketing activities more focused. To this end, they have decided to have kiosks where their products can be exhibited and sold. They intend to place these kiosks at art exhibitions and conferences to target people who are interested in art. However, since they do not have any experience in installing and maintaining kiosks, they have decided to outsource the responsibility to NewTech Marketing. NewTech has installed kiosks for various companies. All these kiosks run on software built using Visual Basic 6.0. However, their central systems, which house the databases and business logic component, are being upgraded to .NET. But for now, they do not intend to upgrade the UI applications that run on the kiosks. When a user using the kiosk wants to make a purchase, he or she has to register by entering his or her details. In case the user has registered earlier, he or she can simply log in giving the login name and password. A component that will allow a user to register, log in, or change the password for the login has to be built.

IMPLEMENTATION OF COM AND .NET INTEROPERABILITY Chapter 26 779

Project Life Cycle

The development life cycle of a project, as discussed in Chapter 8, usually involves three phases:

Project initiation

Project execution

Project deployment

In the project-initiation phase, the project plan was prepared and the development team for the project was identified. The development team further prepared a comprehensive list of tasks involved in the execution and the deployment phases of the project’s life cycle.

Moving further, you will look at the tasks performed by the development team in the following stages of the project execution phase:

Requirements analysis

Design

Construction

Testing

The following sections detail the tasks performed by the team in each of these stages.

Requirements Analysis

In the requirements-analysis phase, the NewTech team analyzed the use of the Login screen in the kiosk and the features to be provided to the screen. After analyzing the same, the team came up with the following list of requirements:

A component has to be created to house the business logic for supporting the registration/login feature of the kiosk application.

The component should expose methods that allow a user using the kiosk to register, log in, and change his or her password.

The component created should be accessible from the existing kiosk application, developed using Visual Basic 6.0.

Since the central server at NewTech is being upgraded to the .NET platform, the component should be created as a .NET assembly.