There are some other miscellaneous keywords and features added to the VC++ .NET compiler and linker that make writing code for the .NET Framework possible. These features include new pragma keywords, preprocessor directives, and compiler and linker flags.
Two pragma statements make it possible to write new .NET applications that utilize existing legacy code. The first pragma, managed, tells the compiler that the code enclosed within the pragma should be compiled as managed .NET code. This pragma is used when .NET Framework code appears within your legacy C++ applications.
The second pragma, unmanaged, does the opposite: It tells the compiler the code within the pragma should be compiled as unmanaged or regular C++ code. When writing a .NET application in VC++ .NET, you can switch back to the standard C++ compiler for part of the application with this pragma. You will learn about the issues involved with mixing managed and unmanaged code within an application in a later hour's lesson. The code in Listing 2.1 shows the use of the managed and unmanaged pragmas.
1: // must be compiled with /clr compiler option 2: 3: // for managed code 4: #using <mscorlib.dll> 5: 6: // for use with the unmanaged code 7: #include <stdio.h> 8: 9: //Managed code by default 10: void ManagedFunction(void) 11: { 12: System::Console::WriteLine("Managed function.\n"); 13: } 14: 15: // turn off managed code 16: #pragma unmanaged 17: 18: void UnmanagedFunction(void) 19: { 20: printf("Unmanaged function.\n"); 21: } 22: 23: // turn managed code back on 24: #pragma managed 25: 26: void main() 27: { 28: ManagedFunction(); 29: UnmanagedFunction(); 30: }
As you can see from this example, it is possible to create an application with mixed code and control the compiler with the managed and unmanaged pragmas.
Another very useful pragma that you should use in virtually every application you create is once. This pragma placed at the top of any file tells the compiler to only load the file once. This is extremely useful in header files to keep them from being included more than once through redundant references. It eliminates the practice of using a definition as a tag and checking for that definition within the header. The following code shows an example of how you would previously enforce the inclusion of a file only once:
#ifndef MY_INCLUDE #define MY_INCLUDE // The include file contents #endif
This code is now replaced with the #pragma once statement, as shown in the following code segment:
#pragma once // The include file contents
Writing managed C++ code for the .NET Framework requires you to use other assemblies (usually DLLs) in order to provide the basic features of the .NET Framework. It is also common to include your own assemblies or third-party ones to provide additional functionality.
Specifying what assemblies your application uses is done with the #using preprocessor directive. It is very similar to the #include directive, except that it doesn't include a source file. Instead, it actually includes the definition of the assembly, known as the assembly manifest. This manifest describes the namespaces, types, enumerations, and methods defined for use within the assembly.
After specifying which assemblies your code will access, you have to specify which namespaces within those assemblies you plan on using. This is accomplished with the using keyword. Without these declarations, anything you use from an included assembly must be fully referenced with the namespace. For example, if you use the MyComponents.DLL assembly, which includes a Simple namespace with a SimpleClass type, the fully qualified reference is MyComponents.Simple.SimpleClass. If your code references this type more than a few times, it is better to use a namespace. The following code shows an example of how to use the using keyword:
#using <mscorlib.dll> #using <System.dll> #using <MyComponents.dll> using namespace System; using namespace System::ComponentModel; using namespace MyComponents::Simple;
There are a few new compiler options for writing managed .NET code in Visual C++ .NET. However, only one option is required to actually compile an application as a .NET Framework application: /clr.
The /clr option tells the compiler to compile the code for the common language runtime (CLR). All code within the project defaults to managed code unless you specify otherwise with the pragma described earlier.
The /clr option also has an optional :noassembly directive that specifies that the assembly manifest that describes the assembly should not be inserted into the resulting output file. When an assembly manifest is not inserted into the file, the default file extension produced by the compiler is .netmodule, and it can only be used when the output file type is a DLL. The /NOENTRY linker option described in the next section must also be used with this directive.
The other two new compiler options deal with the #using keyword described earlier. The first is the /AI option, which allows you to specify a search path for the files included in your application with the #using keyword.
The second switch, /FU, replaces the #using keyword by telling the compiler to use a filename within the application. Therefore, you don't have to explicitly use the files within your source. In order for this option to work, you must turn off the Force #using property in the compiler settings for the project.
The new linker options allow you to customize the linking of your managed .NET Framework modules. The first, /NOASSEMBLY, produces a module that is not an assembly by itself, but can be added to an assembly. This option is redundant with the /clr:noassembly directive described earlier and has the same effect.
The /ASSEMBLYMODULE:filename linker option is used when you have a module that is not part of an assembly. This option binds the module to the specified assembly. Although the code within the assembly that the module is bound to cannot access the module code, any application that uses the resulting assembly can access everything within the assembly.
The last link option, /ASSEMBLYRESOURCE:filename, allows you to bind a .NET Framework resource file to an assembly. These resources are then accessed with the System.Resources namespace classes. The resource file has a .resources extension and is generated by the Resource File Generator (RESGEN.EXE) or in the development environment.
Top |