Search code examples
c#.netwindowswinformsngen

NGEN Display Returns A different result than Elevated CMD when run using Process.Start() in C# winforms


i have been trying to figure this out with my co-workers for a while now.
i use Ngen to Make Native images and boost my Applications performance on the clients.
lets assume the Exe Filename is Example.exe
what i try to do in the app is that i do ngen install example.exe,and the ngen will install native images for the assebmlies
however here is the problem :
if i try an Elevated CMD and run
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\ngen Display example.exe
the example.exe file name and the version of the native image is displayed,however,using the following code which does the same thing in the windows forms c#,it does not display the filename and version of the example.exe file,and displays the dependencies instead,such as Telerik and so on.
so my question is why does the CMD return the correct result while the process returns the dependencies instead of the filename and version itself?
here is some of my code:

public static bool Run()
        {

            var f = new Loading();

            bool state = false;

            var b = new BackgroundWorker();

            string runtimeStr = RuntimeEnvironment.GetRuntimeDirectory();
            string ngenStr = Path.Combine(runtimeStr, "ngen");

            Process process = new Process
            {
                StartInfo =
                {
                    FileName = ngenStr,
                    WindowStyle = ProcessWindowStyle.Hidden,
                    UseShellExecute = false,
                    RedirectStandardOutput = true,
                    RedirectStandardError = true,
                    CreateNoWindow = false
                }
            };

            if (Environment.OSVersion.Version.Major >= 6)
            {
               process.StartInfo.Verb = "runas";
            }
            process.StartInfo.Arguments = "display " + Application.ProductName;

            process.Start();
           // process.WaitForExit();

            string stdoutx = process.StandardOutput.ReadToEnd();
                process.WaitForExit();
}


however the stdoutx string does not contain the example.exe filename or version
EDIT : examples of what should be and what is :
this is what the cmd returns which is the correct result :

Example, Version=1.0.0.19, Culture=neutral, PublicKeyToken=null <debug>


this is what is :

Microsoft (R) CLR Native Image Generator - Version 4.6.79.0
Copyright (c) Microsoft Corporation.  All rights reserved.

NGEN Roots:

C:\Project\Example\bin\Debug\Example.EXE 

NGEN Roots that depend on "Example":

C:\Project\Example\bin\Debug\Example.EXE 

Native Images:

Klik.Windows.Forms.EntryLib.V2.2008, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null
Microsoft.CSharp, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.CSharp, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.CSharp, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
NCalc, Version=1.3.8.0, Culture=neutral, PublicKeyToken=973cde3f1cafed03
Newtonsoft.Json, Version=6.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed
Newtonsoft.Json, Version=6.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed
Newtonsoft.Json, Version=6.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed
RedGate.Migrations.Core, Version=1.0.0.1401, Culture=neutral, PublicKeyToken=7f465a1c156d4d57 <debug>
RedGate.Shared.ComparisonInterfaces, Version=1.0.2.278, Culture=neutral, PublicKeyToken=7f465a1c156d4d57
RedGate.Shared.SQL, Version=9.9.0.0, Culture=neutral, PublicKeyToken=7f465a1c156d4d57
RedGate.Shared.Utils, Version=9.9.0.0, Culture=neutral, PublicKeyToken=7f465a1c156d4d57
RedGate.SOCCompareInterface, Version=3.0.50.59, Culture=neutral, PublicKeyToken=7f465a1c156d4d57
RedGate.SQLCompare.ASTParser, Version=11.0.0.414, Culture=neutral, PublicKeyToken=7f465a1c156d4d57
RedGate.SQLCompare.Engine, Version=11.1.0.2, Culture=neutral, PublicKeyToken=7f465a1c156d4d57 <debug>
RedGate.SQLCompare.Rewriter, Version=11.1.0.2, Culture=neutral, PublicKeyToken=7f465a1c156d4d57
System.Configuration.Install, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
System.Data.DataSetExtensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
System.Data.Linq, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
System.Data.SQLite, Version=1.0.85.0, Culture=neutral, PublicKeyToken=db937bc2d44ff139
System.Deployment, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
System.Management, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
System.Runtime.Serialization, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
System.ServiceModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
System.Threading, Version=1.0.2856.102, Culture=neutral, PublicKeyToken=31bf3856ad364e35
System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
System.Xml.Linq, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
Telerik.Reporting, Version=9.0.15.324, Culture=neutral, PublicKeyToken=a9d7983dfcc261be
Telerik.ReportViewer.WinForms, Version=9.0.15.324, Culture=neutral, PublicKeyToken=a9d7983dfcc261be
Telerik.WinControls.ChartView, Version=2015.1.331.40, Culture=neutral, PublicKeyToken=5bb2a467cbec794e
Telerik.WinControls, Version=2015.1.331.40, Culture=neutral, PublicKeyToken=5bb2a467cbec794e
Telerik.WinControls.GridView, Version=2015.1.331.40, Culture=neutral, PublicKeyToken=5bb2a467cbec794e
Telerik.WinControls.Themes.Office2010Black, Version=2015.1.331.40, Culture=neutral, PublicKeyToken=5bb2a467cbec794e
Telerik.WinControls.Themes.Office2010Silver, Version=2015.1.331.40, Culture=neutral, PublicKeyToken=5bb2a467cbec794e

Solution

  • Yes, you are not doing this correctly. The syntax of the command you are using is:

     ngen.exe display [assemblyName | assemblyPath]
    

    Note the difference between assemblyName and assemblyPath. When you ran it from cmd.exe you typed "example". And thus specified the (partial) assembly name. In your code, you used "example.exe". And the Environment.CurrentDirectory is set correctly by accident, a common accident. So Ngen.exe can find the file and it gets chatty. Listing not just the assembly name but also the native images for all of its dependencies. Like Klik.Windows.Forms.EntryLib etcetera.

    Not the only problem, note that you specified the partial assembly name. You want to make sure that the specific version of your assembly was ngen-ed. Make the code look like this instead:

        process.StartInfo.Arguments = "display \"" + 
            System.Reflection.Assembly.GetEntryAssembly().FullName + "\"";
    

    And test it with Project > Properties > Debug tab > untick the "Enable the Visual Studio hosting process" checkbox.

    Secondary things to fret about are the bitness of the native images (x86 vs x64) and getting your app elevated so you can install the native images, something you normally only have a shot at when your app is installed.