Migrating Unmanaged Applications to. NET
Published year: 2004
Migrating Unmanaged Applications To .NET
Copyright 2004 by SkillSoft Corporation
All rights reserved. No part of this work may be reproduced or transmitted in any form or by any means, electronic or mechanical, including photocopying, recording, or by any information storage or retrieval system, without the prior written permission of SkillSoft.
Trademarked names may appear in the InstantCode series. Rather than use a trademark symbol with every occurrence of a trademarked name , we use the names only in an editorial fashion and to the benefit of the trademark owner, with no intention of infringement of the trademark.
Published by SkillSoft Corporation
20 Industrial Park Drive
Nashua , NH 03062
The information in this book is distributed on an "as is" basis, without warranty. Although every precaution has been taken in the preparation of this work, neither the author nor SkillSoft shall have any liability to any person or entity with respect to any loss or damage caused or alleged to be caused directly or indirectly by the information contained in this work.
.NET provides a framework to develop several types of applications, such as Windows and Web-based applications, and applications for console and mobile devices. There are various types of .NET applications, such as Active Server Pages (ASP) .NET, Visual Basic (VB) .NET, Visual C++ (VC++) .NET, and ActiveX Data Objects (ADO) .NET.
This chapter describes the .NET Framework and explains how .NET Framework executes code of your applications. In addition, it describes the various features provided by ASP .NET, VB .NET, VC++ .NET, and ADO .NET.
The .NET Framework provides an integrated and well-managed environment to develop and execute stand-alone and distributed applications using different types of projects. For example, you can create a Web application or a Web service that provides real-time stock updates on a Personal Digital Assistant (PDA) or a mobile phone.
The .NET architecture consists of two main components , the Common Language Runtime (CLR) and the .NET Framework Class Libraries. Figure 1-1 shows the architecture of .NET.
Figure 1-1: The .NET Architecture
CLS ensures interoperability between languages. CTS makes your applications robust and the class libraries provide reusable components for your application. CLR provides the runtime for executing .NET applications.
The .NET languages reside at the topmost tier and have the highest level of abstraction in the .NET architecture. The CLR resides at the bottom tier and is at the lowest level of abstraction in the .NET architecture.
CLR provides the run-time environment for loading and executing .NET applications. In addition, it provides the core functionality to the .NET Framework, such as language interoperability, exception handling, security, debugging, automatic memory management, version support, type safety, and thread management.
CLR supports multiple languages, such as VB, C# (C Sharp), and C++ with managed extensions.
Managed extensions to C++ extend the syntax of C++ to develop C++ applications on the .NET platform.
To ensure interoperability between modules written in different languages, CLR includes CLS, which provides a set of specifications or guidelines to which all .NET compliant languages must conform. CLS ensures that any source code, written in a CLR-supported language, interoperates within the .NET Framework if compiled successfully by a .NET compiler. For example, an application written in VB.NET can reference a Dynamic-Link Library (DLL) written in C#. As a result, you can integrate modules written in different languages in one application. This helps develop reusable applications.
To learn more about language interoperability, see the Language Enhancements in .NET ReferencePoint.
CLR supports exceptions and eliminates the need to check the successful execution of each step in a complex sequence of operations. If an operation fails, CLR automatically transfers the code to the appropriate error handler. Code execution resumes only after the error is resolved. The error handler tries to rectify the error by itself. If it fails to do so, it generates an error message to help the developer debug the code. For example, if the code contains a division by zero operation, CLR raises an exception and diverts the execution to the exception handler.
CLR also provides a unified debugger that allows you to debug applications written in multiple languages. These applications may run locally or on remote computers.
automatically allocates the memory required by an object in .NET applications. In addition, CLR supports automatic garbage collection to release all the resources the program no longer uses. Automatic garbage collection helps quickly allocate memory and improves the performance of code by allocating memory in consecutive and adjacent blocks. The code also becomes smaller, simpler, and more reliable because it need not de-allocate memory explicitly.
collection helps prevents memory leakage that could occur if you accidentally reference the memory that has already been freed. The garbage collector manages objects on a heap, which reduces the time spent by the system to repeatedly check if an object is still active.
A heap is a section of memory that is reserved for creating reusable objects.
To learn more about garbage collection, see the Garbage Collection Mechanism in .NET Framework ReferencePoint.
To make the code secure and reliable, CLR uses CTS to perform strict type checking of the code during compilation. CTS defines the different data types along with their supported operations. CTS also ensures type compatibility between different .NET components and helps achieve cross language integration by transferring data between components. For example, both the Visual Basic Integer and the C# int compile to a System.Int32 type. This eliminates the need for time-consuming data conversions between components created in different languages. You cannot use the CTS-defined types directly in your application to declare variables . For example, you cannot declare an integer variable as the CTS-defined type, System.Int32. These CTS-defined types are the underlying types to which the specific data types of each .NET compliant language compile. All .NET types fall in one of the following two categories:
Value types: Are the basic built-in data types, such as Boolean, Char, String, or Object. These types have short life spans . The .NET runtime allocates memory for these types on the stack, which is a separate area of the memory dedicated to the execution of the application. Value types are passed between functions by value. This means that the changes the called function makes to their values do no get reflected in the calling function.
Reference types: Are pointers to the memory locations where the values of the data types reside. For example, classes, arrays, and interfaces are reference types in .NET applications. These types are allocated on the heap and the garbage collector manages their life cycle. Reference types are passed between functions by reference. This means that the changes the called function makes to the passed values are reflected in the calling function. This is because the called function can directly refer to the locations where these values reside.
You can use multithreading supported by CLR to develop high-performance interactive applications that can perform several tasks simultaneously . A thread is a lightweight process you create within a program. The thread shares the program’s resources, such as global and static variables, or address space, with other threads in the same program. The operating system assigns time slices to different programs. Multiple threads in a program share the time slice allotted to that program. You can assign priorities to different threads in your program to ensure that high priority tasks take precedence over low priority ones. When the time slice assigned to a thread expires , the thread saves its context. As a result, the next time that thread is loaded into the memory, it loads the saved context and resumes execution from the point it was suspended .
Multithreading enhances application performance by improving its response time because the processor does not waste time waiting for complex operations to finish execution. In that idle time, the processor executes other tasks.
uses the just-in-time compiler or jitter to improve the run-time performance of .NET applications. All applications created in the .NET Framework compile to a low-level, platform-independent language called the Microsoft Intermediate Language (MSIL). At the time of execution, the jitter converts the MSIL code into the platform-specific binary code. This binary code is native to the computer on which you run the .NET application. There is a separate jitter for each type of hardware supported by the .NET Framework. The main advantage of using the jitter is that it does not convert the entire MSIL code into its native binary at once. The jitter compiles only the called methods from the MSIL code to binary ahead of the execution of those methods . In addition, the jitter compiles each section of the code to binary only once during the execution of the application and stores the resultant binary code in a local cache. Subsequent calls to the method skip the compilation process and use the local cache to serve requests . As a result, the jitter helps conserve system resources, such as memory.
CLR provides a run-time environment for executing the .NET application. There are two types of code, managed and unmanaged. You develop managed code using a language compiler that targets the CLR for code execution. The code you develop without considering the conventions and requirements of the CLR is called unmanaged code.
Table 1-1 describes the differences between a managed and an unmanaged application:
Compiles to MSIL and metadata.
Compiles to the respective object files.
Always has metadata that contains all the information about the classes, structures, and interfaces employed by the program.
Does not have metadata.
Eliminates the need to use the Registry, the Interface Definition Language (IDL), and type libraries to store information about the application. Metadata performs this task.
Needs to use registry files, IDL, and type libraries to store information about the application.
Uses all the services offered by CLR, such as garbage collection, exception handling, and version support.
Uses only some of the services offered by CLR, if the CLR environment runs the unmanaged code. Otherwise, it does not use any service. For example, unmanaged code may run with limited debugging and without garbage collection.
To learn more about CLR, see the Basics of .NET Framework ReferencePoint.
The class library of the .NET Framework consists of a comprehensive object-oriented collection of reusable interfaces, types, and classes. You can use these reusable components to develop applications ranging from command-line or GUI applications to Web applications and Web services built using ASP.NET.
The components of the class library allow you to access different system services, such as file operations, input/output, database access, and remoting that helps establish communication between components on remote systems. The .NET Framework class libraries are CLS-compliant. As a result, all CLS-compliant programming languages, such as C#, VB.NET, JScript .NET, Visual J#, and managed extensions to C++, can easily use the .NET Framework classes.
The types included in the class library of the .NET Framework are extensible. This means that you can add your own functionality to these types to create new types.
The .NET Framework class library includes managed classes that are organized into namespaces, which are contained within assemblies.
Namespaces are logical groupings of types, classes, and interfaces that provide related functionality, and are accessible to languages that target the .NET Framework. For example, you can access classes related to the input/output function in the namespace, System.IO.
Namespaces allow you to organize classes to facilitate their use in other applications. In addition, namespaces help avoid naming conflicts between classes that have the same names . As a result, an application can have two classes with the same name , if they belong to different namespaces.
All the classes in a given namespace are unique. The .NET Framework organizes the classes in a hierarchical order in the namespaces. To define the hierarchical view, the .NET Framework uses a dot (.) as a delimiter between the different levels of hierarchy. At the root of the .NET Framework is the System namespace. You can access the other namespaces using the dot operator. For example, to access the Console class of the System namespace, you need to use the System.Console namespace. You need to import the namespace into an application to access the functionality of the classes that belong to that namespace. Some of the namespaces that you can include in .NET applications are System, System.Collections, System.Data, System.IO, System.Net, System.Security, System.Xml, Microsoft.Csharp, Microsoft.Jscript, Microsoft.Win32, and Microsoft.VisualBasic. Listing 1-1 shows how to use namespaces in .NET:
Listing 1-1: Using Namespaces in .NET
Public Sub Display() System.Windows.Forms.MessageBox.Show("Hello, world!") System.Console.WriteLine("Hello, world") End Sub
The above listing shows a Display() method that uses the namespaces, System and System.Windows.Forms.
Listing 1-2 shows how to simplify the code in Listing 1-1:
Listing 1-2: Simplifying Use of Namespaces in .NET
Imports System Imports System.Windows.Forms Public Sub Display() MessageBox.Show("Hello, world!") Console.WriteLine("Hello, world") End Sub
The above listing shows how to import the System and System.Windows.Forms namespaces into your code. This allows you to use the classes in these namespaces, without prefixing the classes with the entire namespace hierarchy.
An assembly is the basic unit to which all .NET applications compile. The assembly does not contain directly executable machine instructions. Instead, the assembly is a standard Portable Executable (PE) .dll or .exe file that includes one or more modules. Each module contains the MSIL code of your application and the metadata that describes the code. The metadata in the assembly, also called the assembly manifest, contains all the information about the assembly, such as:
A list of the types included in the assembly
Implementation of classes, structures, and interfaces
Name and version number of the assembly
Security information about the assembly, such as the Code Access Security (CAS) permissions, which define the permissions allowed to the assembly, and the permissions denied to the assembly
Dependency information that includes a list of other assemblies required by an assembly
A list of all the files that constitute the assembly
Each assembly has a manifest. The assembly manifest can reside in a separate file or within a module of the assembly. CLR receives all the information it requires to execute an application from the application’s assemblies and metadata. For example, if an application is using a component, the assembly keeps track of the version number of the component and provides this information to the CLR during application execution.
To learn more about .NET Framework class libraries, see the Basics of .NET Framework ReferencePoint.
CLR executes the managed applications created using .NET. When you compile and execute the managed code:
The compiler provided by the .NET Framework SDK or Visual Studio .NET, translates the source code of the .NET application into MSIL or Intermediate Language (IL), instead of the machine-level code.
The compiler also produces metadata about the program while it is compiling.
An assembly links the IL and the metadata. The assembly does not consist of directly executable machine instructions. It is a file with .exe or .dll extension. The CLR executes these assemblies.
When the CLR executes the .EXE or .DLL file, the class loader loads the code into memory and parses the metadata information in the assemblies. This enables the CLR to discover the dependencies, if any, in the assemblies.
The jitter translates the code from MSIL into binary code, native to the computer on which the application executes. This binary code is directly executable. The CLR supplies a jitter for each supported CPU. During compilation, the jitter compiles only the code that is required during execution instead of compiling the complete IL code at once.
The jitter converts the IL for a method into native code when the code makes its first call to that method.
The jitter also stores the address of the compiled code of a method. For subsequent requests to the compiled method, the jitter directly executes the compiled code from the stored address.
The jitter also checks the code for type safety to ensure compatible access to objects. For example, if you pass an eight-byte value to a method that accepts a four-byte value, the CLR detects and traps the attempt.
After translating the IL into native code, the converted code is sent to the .NET runtime manager.
The .NET runtime manager executes the code. While doing so, the runtime manager performs a security check to ensure that the code has the appropriate permissions for accessing the resources.
Figure 1-2 shows how a .NET application is executed using CLR:
Figure 1-2: Compilation and Execution of a .NET Application
Migrating Unmanaged Applications to. NET
Published year: 2004