Microsoft’s C#, Visual Basic, JScript, J#, and the IL Assembler always produce managed modules that require the CLR to execute. End-users must have the CLR installed on their machine in order to execute any managed modules, in the same way that they must have the Microsoft Foundation Class (MFC) library or Visual Basic DLLs installed to run MFC or Visual Basic 6 applications.
By default, Microsoft’s C++ compiler builds unmanaged modules: the EXE or DLL files that we’re all familiar with. These modules don’t require the CLR in order to execute. However, by specifying a new command-line switch, the C++ compiler can produce managed modules that do require the CLR to execute. Of all the Microsoft compilers mentioned, C++ is unique in that it is the only language that allows the developer to write both managed and unmanaged code and have it emitted into a single module. This can be a great feature because it allows developers to write the bulk of their application in managed code (for type safety and component interoperability) but continue to access their existing unmanaged C++ code.
Combining Managed Modules into Assemblies
The CLR doesn’t actually work with modules; it works with assemblies. An assembly is an abstract concept that can be difficult to grasp initially. First, an assembly is a logical grouping of one or more managed modules or resource files. Second, an assembly is the smallest unit of reuse, security, and versioning. Depending on the choices you make with your compilers or tools, you can produce a single-file or a multifile assembly.
Chapter 2, I’ll go over assemblies in great detail, so I don’t want to spend a lot of time on them here. All I want to do now is make you aware that there is this extra conceptual notion that offers a way to treat a group of files as a single entity.
Figure 1-2 should help explain what assemblies are about. In this figure, some managed modules and resource (or data) files are being processed by a tool. This tool produces a single PE file that represents the logical grouping of files. What happens is that this PE file contains a block of data called the manifest. The manifest is simply another set of metadata tables. These tables describe the files that make up the assembly, the publicly exported types implemented by the files in the assembly, and the resource or data files that are associated with the assembly.
Figure 1-2 : Combining managed modules into assemblies
By default, compilers actually do the work of turning the emitted managed module into an assembly; that is, the C# compiler emits a managed module that contains a manifest. The manifest indicates that the assembly consists of just the one file. So, for projects that have just one managed module and no resource (or data) files, the assembly will be the managed module and you don’t have any additional steps to perform during your build process. If you want to group a set of files into an assembly, you’ll have to be aware of more tools (such as the assembly linker, AL.exe) and their command-line options. I’ll explain these tools and
options in Chapter 2.
An assembly allows you to decouple the logical and physical notions of a reusable, deployable, versionable component. How you partition your code and resources into different files is completely up to you. For example, you could put rarely used types or
resources in separate files that are part of an assembly. The separate files could be downloaded from the Web as needed. If the files are never needed, they’re never downloaded, saving disk space and reducing installation time. Assemblies allow you to
break up the deployment of the files while still treating all the files as a single collection.
An assembly’s modules also include information, including version numbers, about referenced assemblies. This information makes an assembly self-describing. In other words, the CLR knows everything about what an assembly needs in order to execute. No additional information is required in the registry or in Active Directory. Because no additional information is needed, deploying assemblies is much easier than deploying unmanaged components.
Loading the Common Language Runtime
Each assembly that you build can be either an executable application or a DLL containing a set of types (components) for use by an executable application. Of course, the CLR is responsible for managing the execution of code contained within these assemblies. This means that the .NET Framework must be installed on the host machine. Microsoft has created a redistribution package that you can freely ship to install the .NET Framework on your customers’ machines. Eventually, the .NET Framework will be packaged with future versions of Windows so that you won’t have to ship it with your assemblies.
You can tell if the .NET Framework has been installed by looking for the MSCorEE.dll file in the %windir%\system32 directory. The existence of this file tells you that the .NET Framework is installed. However, several versions of the .NET Framework can be installed on a single machine simultaneously. If you want to determine exactly which versions of the .NET Framework are installed, examine the subkeys under the following registry key:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework\p o l i c y
When you build an EXE assembly, the compiler/linker emits some special information into the resulting assembly’s PE file header and the file’s .text section. When the EXE file is invoked, this special information causes the CLR to load and initialize. The CLR then locates the application’s entry point method and allows the application to start executing.
Similarly, if an unmanaged application calls LoadLibrary to load a managed assembly, the DLL’s entry point function knows to load the CLR in order to process the code contained within the assembly.
For the most part, you don’t need to know about or understand how the CLR gets loaded. For most programmers, this special information allows the application to just run, and there’s nothing more to think about. For the curious, however, I’ll spend the remainder of this section explaining how a managed EXE or DLL starts the CLR. If you’re not interested in this subject, feel free to skip to the next section. Also, if you’re interested in building an unmanaged application that hosts the CLR, see Chapter 20.
Figure 1-3 summarizes how a managed EXE loads and initializes the CLR.