How Is a Visual Basic .NET Program Put Together?

How Is a Visual Basic .NET Program Put Together?

The first step in building a Visual Basic .NET program is to compile Visual Basic .NET source code as managed code. The compiler translates the source code into Microsoft Intermediate Language (MSIL). MSIL is a CPU-independent set of instructions that can be efficiently converted to native code. MSIL is rich in various instructions that define loading, storing, initializing, calling, arithmetic and logic operations, control flow, memory access, exception handling, and more. All code based on MSIL executes as managed code.

MSIL can't be executed by itself, however; it's an intermediate language not too dissimilar in concept from classic Visual Basic P-code. Every .NET language emits MSIL code when compiled. The MSIL does not know or care what language it was generated from, so the second step in building a program is to run the MSIL through the just-in-time (JIT) compiler to make it platform specific. (The JIT compiler is described in more detail shortly.) Because the CLR provides one or more JIT compilers for each computer architecture, the same MSIL can be JIT-compiled and executed on any architecture supported by the runtime.

Metadata—Data About Data

When the Visual Basic compiler (or any .NET language compiler) produces MSIL from the source code, it also produces what is called metadata. Metadata (data about data) describes the types used in your source code. Metadata is stored in a file called a manifest, which includes the definition of each type, the signatures of each type's members, the members that your code references, and all the other data that the runtime needs at execution.

Metadata is completely self-describing. The type libraries Visual Basic 6 programmers have come to know and love are no longer necessary. Metadata also obviates the need to add complicated and error-prone references to the system registry, as you had to do in Visual Basic 6.

Metadata is generated by the compiler from Visual Basic source code and is stored in the executable in binary format. Metadata is a requirement of .NET. It specifies what types are exported and what types are referenced. It includes the security permissions needed to run the code. It also describes the base classes used, the interfaces implemented, and the visibility of each type. All methods, fields, properties, events, and nested types are fully defined. In addition, a programmer can add custom attributes such as the author or other nonexecutable comments.

With the metadata, the runtime now has all that it needs to locate and extract the code from the MSIL as necessary during execution. The MSIL and its metadata are wrapped up in a portable executable (PE) file.

The Just-In-Time Compiler

Most of us have read about the concept of just-in-time (JIT) inventory, made popular by Japanese businesses. This concept, directed at cost savings, is that inventory for the production of goods should be delivered to the factory minutes before it is used. Following this concept, no excess inventory is stocked—parts are purchased and used on demand. If market forces change materially so that the parts are no longer in demand, no oversupply is left rusting in the warehouse. Of course, the manufacturing company only pays for the parts that are delivered and used.

The idea behind JIT compilation is similar to the inventory story. We know that in most large software programs, some code might never be called during execution. For example, I often use Microsoft Word. While my spelling-checker gets hot from overuse, I have never touched the mail merge feature. In fact, I don't even know how it works or even how to find it. So in .NET-managed programs, rather than using time, CPU cycles, and memory to convert all of the possibly large MSIL to native code for the architecture it is running on, only the code needed during execution is converted. The native code that is compiled is stored so that it's available in compiled form when it is called again.

Just-in-time compilation works something like this. A loader creates and attaches a stub to each of the data type's methods when the type is loaded into memory. On the initial call to the method, the stub passes control to the JIT compiler, which takes the MSIL for that method and converts and optimizes it to native code. The compiler then modifies the stub to direct execution to the location of the native code on subsequent calls. All in all, this reduces the time it takes to JIT-compile and execute the code. Interesting, eh?

Of course, as part of compiling the MSIL to native code, the code must pass a strict verification process. The MSIL and associated metadata is closely examined to determine whether the code is type-safe, meaning that the code can only access memory locations it is authorized to access. As I mentioned earlier, type-safe code prevents malicious or just sloppy code from doing any damage. Type safety is enforced to ensure that objects are safely partitioned from each other to prevent corruption and to ensure your code is robust.

Execution of Visual Basic .NET Code

The CLR provides the infrastructure that enables code execution to take place. During execution, managed code receives services such as automatic memory management, security, interoperability with unmanaged code, cross-language debugging support, and enhanced deployment and versioning support from the runtime.

Take a moment to examine Figure 1-4. While you are writing source code in Visual Basic .NET, another programmer might write code in C++ or C#. Each specific compiler will generate a standardized MSIL module with the .NET types that the specific language permits and exposes to the programmer. But as I mentioned, each exposed type is a member of a subset of all types available in the runtime. Finally, the MSIL module (along with the metadata) is compiled by the Visual Basic .NET JIT compiler in the runtime for the specific architecture it is running on. Native code is generated on demand and executed.

Overview of the life of a Visual Basic .NET program.

Assemble the Troops

In .NET software development, a module is an executable file. A module can be either a library or an executable. Modules usually have either a .dll or an .exe file extension. An assembly is a logical set of one or more modules. I say logical because an assembly will consist of one or more files (such as DLLs, EXEs, HTMLs) that are required to run your application. The assembly has to know exactly what is included in this group.

If you think of a UPS driver who delivers many packages to many customers around town, the driver needs to know what packages are on the truck and who receives them. Typically, drivers rely on a paper manifest to list the contents of the truck and possibly the location of specific packages on the truck. The .NET Framework uses this same logic. Included in the assembly is the manifest, which contains the metadata. The manifest contains a listing of what files are in the assembly as well as where to locate each item. When the runtime loads a program, it locates the assembly and attempts to resolve an assembly reference. The term probing is often used when discussing how the runtime locates assemblies. The runtime refers to the set of heuristics used to locate the assembly on the basis of its name and culture (country format).

It's important to note than an assembly is the smallest unit of executable code that can be deployed (or versioned for that matter). When we deploy code, only assemblies have version numbers. Shortly I'll show you a manifest and an assembly to give you a flavor of how they work. But enough theory for the moment. Let's set up the IDE, build a small Visual Basic .NET program, and look at the files that are created.



Coding Techniques for Microsoft Visual Basic. NET
Coding Techniques for Microsoft Visual Basic .NET
ISBN: 0735612544
EAN: 2147483647
Year: 2002
Pages: 123
Authors: John Connell

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