Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Autorun Ngen.exe on First Run

My app doesn't have an installer. It is portable but I need to run ngen.exe on it because it runs on startup.

Is it recommended to autorun ngen.exe on the first run of the app? Will it cause any problems later? Is there a built in way to do it?

like image 745
Elmo Avatar asked Mar 22 '23 21:03

Elmo


1 Answers

Is it recommended to autorun ngen.exe on the first run of the app?

I have never read or heard any such recommendation, but it is an interesting idea.

I say go for it and test whether it works for your situation (which is interesting insofar as your "portable"/"no-installer" requirement).

Is there a built in way to do it?

There is not a built-in way to run NGen on the first run of an app; but it can be done as the PoC below demonstrates.

PoC code

The following PoC code incorporates code from a related SO answer.

using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading;

namespace SelfNgenPoC
{
    class Program
    {
        static void Main(string[] args)
        {
            /*
             * Check whether the app has been NGen'd with code adapted from
             * https://stackoverflow.com/a/20593260/1810429, which also outlines
             * an alternative approach - by running...
             *     ngen.exe display <assemblyPath>
             * ...and checking the result - 0 if the app is already NGen'd and
             * -1 if it is not.
             */

            Process process = Process.GetCurrentProcess();

            ProcessModule[] modules = new ProcessModule[process.Modules.Count];
            process.Modules.CopyTo(modules, 0);

            var niQuery =
                from m in modules
                where m.FileName.Contains(@"\" + process.ProcessName + ".ni")
                select m.FileName;
            bool ni = niQuery.Count() > 0 ? true : false;

            // FORNOW: for PoC debugging and sanity checking
            if (ni)
                Console.WriteLine("Native Image: " + niQuery.ElementAt(0));
            else
                Console.WriteLine("IL Image: " + process.MainModule.FileName);

            /*
             * NGen the app if not.
             */

            if (!ni)
            {
                // FORNOW: for PoC debugging and sanity checking
                Console.WriteLine("The app is not NGen'd.");
                Console.WriteLine("NGen'ing the app...");

                var assemblyPath = process.MainModule.FileName;

                ProcessStartInfo startInfo = new ProcessStartInfo();
                // TODO: Determine the path to (the appropriate version of)
                // ngen.exe.
                // FORNOW: Just use a hardcoded path to ngen.exe for PoC.
                startInfo.FileName =
                    @"C:\Windows\Microsoft.NET\Framework\v4.0.30319\ngen.exe";
                startInfo.Arguments = "install \"" + assemblyPath + "\"";
                // TBD: process options that you think make sense
                startInfo.CreateNoWindow = false;
                startInfo.UseShellExecute = false;
                startInfo.WindowStyle = ProcessWindowStyle.Hidden;

                try
                {
                    using (Process exeProcess = Process.Start(startInfo))
                    {
                        exeProcess.WaitForExit();
                    }
                }
                catch
                {
                    // TBD: error handling that you think makes sense - e.g.
                    // logging or displaying the error, moving on regardless
                    // etcetera.
                }
            }
            else
            {
                // FORNOW: for PoC debugging and sanity checking
                Console.WriteLine("The app is already NGen'd.");
            }

            /*
             * Carry on with whatever your app does.
             */
        }
    }
}

first run

C:\bin\SelfNgenPoC>.\SelfNgenPoC.exe
IL Image: C:\bin\SelfNgenPoC.exe
The app is not NGen'd.
NGen'ing the app...
Microsoft (R) CLR Native Image Generator - Version 4.0.30319.18408
Copyright (c) Microsoft Corporation.  All rights reserved.
1>    Compiling assembly C:\bin\SelfNgenPoC.exe (CLR v4.0.30319) ...

C:\bin\SelfNgenPoC>

subsequent run

C:\bin\SelfNgenPoC>.\SelfNgenPoC.exe
Native Image: C:\Windows\assembly\NativeImages_v4.0.30319_32\SelfNgenPoC\a461633
0444188e116025424c70d15f1\SelfNgenPoC.ni.exe
The app is already NGen'd.

C:\SelfNgenPoC>

Will it cause any problems later?

Whether it makes sense to NGen an assembly depends on many factors, which you can review in an MSDN blog post, NGen documentation on MSDN, an older but relevant "MSDN Magazine" article, and elsewhere.

Ultimately only you know enough about your app to determine whether it makes sense to NGen (any, some, or all of) its assemblies.

Assuming it does make sense in your situation, I don't expect it will cause any distinct problems based on what you have described.

Just be sure to keep standard NGen responsibilities in mind - particularly this one noted in the NGen MSDN documentation...

Images need to be regenerated when the original assembly or one of its dependencies is serviced.

...which should be manageable with a little fancier self-NGen'ing logic.

like image 184
J0e3gan Avatar answered Apr 01 '23 14:04

J0e3gan