3

Just a little setup. We have the .Net framework 3.5, 4.0, 4.5, and 4.6.1 installed.

If we build a .Net application or assembly using .Net framework 3.5 and then we set the app.config to run using a single supported runtime of 4.6.1:

<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1"/></startup>

Which version of the framework is actually being utilized?

This question came from from reading this post: How do I force an application compiled to target .NET Framework 4 to run under .NET framework 4.6.1?. @Hans Passant states that the TargetFrameworkAttribute will dictate how the framework will behave and he talks about there being switches that cause specific code to run, etc.. However, I haven't found anything that explains which version of the core .Net framework will be running in this scenario.

Will any calls to the .Net framework use the .Net 3.5 code base, the .Net 4.0 code base (because of the 4.0 clr version), or will the latest and greatest .Net 4.6.1 code base be run because that is the latest version installed using the clr 4.0?

Edit: To show the manifest that does not specifically state the runtime version.

// Metadata version: v2.0.50727
.assembly extern mscorlib
{
  .publickeytoken = (B7 7A 5C 56 19 34 E0 89 )                         // .z\V.4..
  .ver 2:0:0:0
}
.assembly ConsoleApplicationVersionTest
{
  .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 ) 
  .custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78   // ....T..WrapNonEx
                                                                                                             63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01 )       // ceptionThrows.

  // --- The following custom attribute is added automatically, do not uncomment -------
  //  .custom instance void [mscorlib]System.Diagnostics.DebuggableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggableAttribute/DebuggingModes) = ( 01 00 07 01 00 00 00 00 ) 

  .custom instance void [mscorlib]System.Reflection.AssemblyTitleAttribute::.ctor(string) = ( 01 00 1D 43 6F 6E 73 6F 6C 65 41 70 70 6C 69 63   // ...ConsoleApplic
                                                                                              61 74 69 6F 6E 56 65 72 73 69 6F 6E 54 65 73 74   // ationVersionTest
                                                                                              00 00 ) 
  .custom instance void [mscorlib]System.Reflection.AssemblyDescriptionAttribute::.ctor(string) = ( 01 00 00 00 00 ) 
  .custom instance void [mscorlib]System.Reflection.AssemblyConfigurationAttribute::.ctor(string) = ( 01 00 00 00 00 ) 
  .custom instance void [mscorlib]System.Reflection.AssemblyCompanyAttribute::.ctor(string) = ( 01 00 00 00 00 ) 
  .custom instance void [mscorlib]System.Reflection.AssemblyProductAttribute::.ctor(string) = ( 01 00 1D 43 6F 6E 73 6F 6C 65 41 70 70 6C 69 63   // ...ConsoleApplic
                                                                                                61 74 69 6F 6E 56 65 72 73 69 6F 6E 54 65 73 74   // ationVersionTest
                                                                                                00 00 ) 
  .custom instance void [mscorlib]System.Reflection.AssemblyCopyrightAttribute::.ctor(string) = ( 01 00 12 43 6F 70 79 72 69 67 68 74 20 C2 A9 20   // ...Copyright .. 
                                                                                                  20 32 30 31 36 00 00 )                            //  2016..
  .custom instance void [mscorlib]System.Reflection.AssemblyTrademarkAttribute::.ctor(string) = ( 01 00 00 00 00 ) 
  .custom instance void [mscorlib]System.Runtime.InteropServices.ComVisibleAttribute::.ctor(bool) = ( 01 00 00 00 00 ) 
  .custom instance void [mscorlib]System.Runtime.InteropServices.GuidAttribute::.ctor(string) = ( 01 00 24 34 36 36 31 33 34 32 33 2D 38 39 34 30   // ..$46613423-8940
                                                                                                  2D 34 39 36 65 2D 61 31 37 32 2D 37 36 36 31 31   // -496e-a172-76611
                                                                                                  64 30 66 31 32 32 38 00 00 )                      // d0f1228..
  .custom instance void [mscorlib]System.Reflection.AssemblyFileVersionAttribute::.ctor(string) = ( 01 00 07 31 2E 30 2E 30 2E 30 00 00 )             // ...1.0.0.0..
  .hash algorithm 0x00008004
  .ver 1:0:0:0
}
.module ConsoleApplicationVersionTest.exe
// MVID: {11493526-C9AC-45F0-9784-D7712809998C}
.imagebase 0x00400000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003       // WINDOWS_CUI
.corflags 0x00000001    //  ILONLY
// Image base: 0x00000000010B0000
6
  • Did you check the TargetFrameworkAttribute attribute as Hans stated with ildasm on your exe? What value has it? Commented Aug 3, 2016 at 20:19
  • @rene I have looked through the manifest from ildasm but I do not see where it states that attribute. Is there a specific line that gives that information? Commented Aug 3, 2016 at 20:39
  • You're looking for .custom instance void [mscorlib]System.Runtime.Versioning.TargetFrameworkAttribute::.ctor(string) Commented Aug 3, 2016 at 20:44
  • @rene That does not exist in my manifest. I will update the question in just a second to include the manifest showing what is included. Commented Aug 3, 2016 at 20:45
  • That attribute is probably introduced after 2.0. Your exe is targetting the 2.0 runtime Commented Aug 3, 2016 at 21:02

2 Answers 2

2

We have the .Net framework 3.5, 4.0, 4.5, and 4.6.1 installed

That is not accurate, such a configuration is not possible. The rule is that you can have only one version of .NET 2.0 through 3.5 installed, it targets the v2.0.50727 runtime. And one version of .NET 4.0 through 4.6.2 installed, it targets the v4.0.30319 runtime.

So your machine might have had 4.0 installed. When you installed 4.5 it overwrote the 4.0 install. No trace of it is remaining. 4.5 is quite capable of running programs that target 4.0, Microsoft spent an enormous amount of effort to ensure that 4.5 is backwards compatible with 4.0. And likewise, when you installed 4.6.1 it overwrote 4.5

// Metadata version: v2.0.50727

The ildasm.exe dump you posted clearly shows that the assembly targets the 2.0.50727 runtime. So easy peasy, it is going to run on the 3.5 version. It will run just as well on a 2.0 install, it doesn't use any assemblies that were added in 3.0 and 3.5. Maybe that's your cue, Microsoft increments the framework version when it adds new assemblies. Only when it creates a new runtime version can you have another side-by-side install. That's not very likely to happen anytime soon, not counting .NETCore which took a completely different approach.

Sign up to request clarification or add additional context in comments.

10 Comments

It's not going to run on the 3.5 version if that version isn't installed. With the supportedRuntime setting permitting the use of 4.0, if the older runtime version isn't installed, the program will still run on a newer installation with only 4.0 or higher. And in that case, it will be running using the newer runtime, since that's the only one available. If someone really needs to know what version of the runtime is being used in a running process, they need to check the Environment.Version variable (or inspect the registry and derive that information).
Hmm, not that relevant given the first line in the post. Adding a .config file is not that superior to just adding the framework version. Which is automagic, Windows just offers to install it for you when you start the program. And no, Environment.Version does not tell you anything about the framework version you are using, only the runtime version.
And if they one day remove .NET 3.5? Or run on a different system? Or maybe someone else with the same basic question comes here looking for an answer, but they have a slightly different configuration? Questions and answers are supposed to be useful to future readers, and new Q&A shouldn't duplicate existing Q&A; there's nothing here that adds to the information already available on Stack Overflow.
Then it will offer to put it back again when you start the program of course. Even experienced .NET programmers have trouble distinguishing the framework version from the runtime version. Consider reading the post more carefully, you'll learn something new.
"Then it will offer to put it back again when you start the program of course" -- I haven't done a ton of config testing, but that's not been my experience. The reason I've ever run into the supportedRuntime setting is because I've had situations where I've got a .NET program targeting pre-4.0 which I want to run on a 4.0-or-later system. I just get an error, not an offer to re-install the old .NET. But even if I did get an offer to re-install the old .NET, if I uninstalled it, it was for a reason. Why would I reinstall it when I can run my program fine just by changing a setting?
|
0

You can use ILDasm.exe and parse the output. The below is powershell function I uses all the time, and can be very easily migrated to .net VB/C#. Modify the ILDasm.exe path as per your environment.

function Get-NetFrameworkVersion
{
  param([string]$path)

if($path)
 {

    $ildasmpath = 'C:\Program Files (x86)\Microsoft SDKs\Windows\v8.1A\bin\NETFX 4.5.1 Tools\ildasm.exe'
    $ildasmswitches = '/header /noil /text'

    $netframeworkverspattern="//\s+'v(?<version>[0-9.]+)'\s+Version String"

    $pinfo = New-Object System.Diagnostics.ProcessStartInfo
    $pinfo.FileName = $ildasmpath
    $pinfo.RedirectStandardOutput = $true
    $pinfo.UseShellExecute = $false
    $pinfo.CreateNoWindow = $true

    $pinfo.WindowStyle = [System.Diagnostics.ProcessWindowStyle]::Hidden
    $pinfo.Arguments = '"' + $path + '" ' + $ildasmswitches
    $p = New-Object System.Diagnostics.Process
    $p.StartInfo = $pinfo
    $p.Start() | Out-Null

    $dumpcontent = $p.StandardOutput.ReadToEnd()

    $p.WaitForExit()

    if([string]$dumpcontent -match $netframeworkverspattern)
    {
       $Matches.version
    }

 }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.