
Creating a pre-compiled copy of your application at install time.
One of the biggest complaints about managed code applications such as Windows Forms programs is that they take so long to start. This is because the code is stored in a bytecode form that isn't the same as that used by the microprocessor. Intermediate Language (IL) must be compiled to native form before being used and this initial Just-In-Time, or JIT, compile phase can be lengthy, especially if the program is long and complex. Once the application has been compiled to native code, the framework can cache a copy of that application and use that directly whenever a request is made to use the original IL-encoded executable. Usually, the compilation takes place on the fly as methods and classes are used but the framework provides an application, called NGEN.EXE, that will do the job for you at once. It's therefore possible to call NGEN at install time so that the first time an application is run by the user, the cached copy is already present and the native binary image is loaded thereby shortening the startup time significantly. The framework identifies the cached executables by their strong-name which includes a version number and a public-private key pair that uniquely tags the application. When JIT compiling, if the application is not strong-named the system will assign a key so that the compiled assembly can be identified in subsequent uses. Unfortunately NGEN doesn't do this so to take advantage of this technique the application must have a strong name. This isn't difficult to arrange but it can cause problems if an application uses DLL's or interop assemblies that do not have a strong name. The secret to creating a pre-compiled native code image is in the use of a custom installer DLL that you distribute along with your application. At install time this DLL is invoked by the installer and runs at certain point in the install process. The native code generation process needs to run after the application has been copied to the program files directory. This example uses a single solution containing the dummy .NET application, the custom installer and the setup project all in one place. Follow along with the solution creation steps to see how this is all accomplished. For C# applications the solution will contain a simple Windows Forms application with a strong name, a custom installer written in C# and the setup project. First you need to create a new application in its own solution. For the purposes of this example this is just the simplest form with a label on it. To strong-name the application which is necessary for the native image compiler to create an image first time round we use the strong-name tool to generate a key pair and place this in the project directory. The command line window is used. Open a Visual Studio command prompt, select your project directory and type: sn -k NativeImageExampleApp.snk This will generate the key pair. Now, to sign the assembly containing the application, change the AssemblyInfo.cs file so that the AssemblyKeyFile points to the generated key-file. The following code snippet shows this change. [assembly:
AssemblyDelaySign(false)] Now to create the custom installer. Add a second project to the solution choosing a simple class-library project. Delete the class1.cs file that is automatically generated and now add a new installer-class to the project. In this example the name is left as the default "Installer1.cs". Now, in the body of that class declare an override for the Install virtual method. In this override goes the code that invokes NGEN at install time. At install time the code needs to know certain things that will not be apparent when you're writing the code such as the place where the user has chosen to put the application and so-on. To get this information we can take shortcuts by making a few assumptions such as the fact that the install DLL will be situated in the same directory as the application. If this doesn't suit your own scheme you can of course tweak the idea as you need it. In this example the installer assumes .NET framework 1.1 which is build version 1.1.4322. Using this we can construct the path to the NGEN.EXE application and use the System.Diagnostics.Process class to compile our application to native code. The listing below shows how.
public
override void Install(IDictionary stateSaver) string netdir=sysdir+@"\Microsoft.NET\Framework\v1.1.4322"; string assemblypath=this.Context.Parameters["assemblypath"]; string location=assemblypath.Substring(0,assemblypath.IndexOf(@"custominstaller.dll")) +"nativeimageexampleapp.exe"; if(Directory.Exists(netdir)) Process.Start(netdir+@"\ngen.exe", @""""+location+@""""); base.Install(stateSaver); }
This code will be run automatically after the successful installation of the application.
For VB.NET applications the solution will contain a simple Windows Forms application with a strong name, a custom installer written in VB and the setup project. First you need to create a new application in its own solution. For the purposes of this example this is just the simplest form with a label on it. To strong-name the application which is necessary for the native image compiler to create an image first time round we use the strong-name tool to generate a key pair and place this in the project directory. The command line window is used. Open a Visual Studio command prompt, select your project directory and type: sn -k NativeImageExampleApp.snk This will generate the key pair. Now, to sign the assembly containing the application, change the AssemblyInfo.cs file so that the AssemblyKeyFile points to the generated key-file. The following code snippet shows this change. [assembly:
AssemblyDelaySign(false)] Now to create the custom installer. Add a second project to the solution choosing a simple class-library project. Delete the class1.vb file that is automatically generated and now add a new installer-class to the project. In this example the name is left as the default "Installer1.vb". Now, in the body of that class declare an override for the Install virtual method. In this override goes the code that invokes NGEN at install time. At install time, the code needs to know certain things that will not be apparent when you're writing the code such as the place where the user has chosen to put the application and so-on. To get this information we can take shortcuts by making a few assumptions such as the fact that the install DLL will be situated in the same directory as the application. If this doesn't suit your own scheme you can of course tweak the idea as you need it. In this example the installer assumes .NET framework 1.1 which is build version 1.1.4322. Using this we can construct the path to the NGEN.EXE application and use the System.Diagnostics.Process class to compile our application to native code. The listing below shows how. Public Overrides Sub Install(stateSaver As IDictionary) Dim sysdir As String = Environment.ExpandEnvironmentVariables("%windir%") Dim netdir As String = sysdir + "\Microsoft.NET\Framework\v1.1.4322" Dim assemblypath As String = Me.Context.Parameters("assemblypath") Dim location As String = assemblypath.Substring(0, assemblypath.IndexOf("custominstaller.dll")) + "nativeimageexampleapp.exe" If Directory.Exists(netdir) Then Process.Start(netdir & "\ngen.exe", """" & location & """") End If MyBase.Install(stateSaver) End Sub 'Install
This code will be run automatically after the successful installation of the application. The final piece of the puzzle is the custom install step itself. To create this you must first add a setup and deployment project to the solution and include the project output from both the example application and the custom installer DLL. From the solution explorer, select the installer project and click on the "Custom actions editor" button.
Figure 1. Setting up the custom actions. Then, add a custom action to the "Install" folder:
Figure 2. Specifying the custom action. That's it!. You should now have a Windows Forms application, a custom installer DLL and a setup and deployment project with a custom action included. If you run the install you'll see a command prompt window appear momentarily as the NGEN program compiles the IL to native code, storing it in the cache and just to verify, you can open the Visual Studio command prompt and use NGEN yourself to see that the native image is indeed available using the command line: ngen /show nativeimageexampleapp You will see something like the following:
Figure 3. The native image after install. Summary To get the best performance possible at startup time, especially when first impressions count like just after the customer has downloaded and run the nice new application, it's really nice not to have to wait for the JIT compiler to do it's thing. A large program I worked on recently took 45 seconds to JIT compile after install and the customer thought his machine had crashed. With this technique the first-run time was reduced to a more manageable six seconds which was well within the realms of patience. Return to Windows Forms Tips and Tricks Copyright © Ramuseco Limited 2004-2005 All Rights Reserved.
|