What CLR version am I or me or this?DevFish Chronicles - Finding the desired CLR runtime version of an assembly - >лл(o>Joe Healy - www.devfish.net December 2005 Summary: Recently a large enterprise customer asked me a relatively simple question. Or so I thought. Given a large number of DLLs and executable files, how could they find out what version of the CLR each is targeted for? This was a perplexing question to me in the least, especially since I'd never really given this much thought before or even been asked this before. Scary when stuff like this that you should know, and should be easy to do. ContentsILDASMDUMPBIN Custom Code | ||||||||||
|
I considered the possibilities of two ready to go approaches which might work for them but had a few downsides. If you don't have to write code cause someone else already did it, its a beautiful thing. Each worked, and I'll talk about them below. But each had some drawbacks, in the end, I resorted to some custom code that was actually pretty simple. ILDASMILDASM was my first approach to trying to find the CLR version used by the assemblies. ILDASM is the Intermediate Language Disassembler. Running ILDASM against an assembly enables you to see the metadata which contains the CLR version, as well as the raw IL that comprises the file. Inside the metadata window it will also show you the CLR version used.![]() You may also run ILDASM from a command line. Using the /header flag forces up information about the CLR header and the runtime versions employed. Note this data will also be present in the MetaData commend found later in the MSIL code dump. C:\TEMP\ILDASM clrver.exe /text /header // Microsoft (R) .NET Framework IL Disassembler. Version 2.0.50727.42 // Copyright (c) Microsoft Corporation. All rights reserved. ... LOTS OF STUFF DELETED HERE ... // ----- CLR Header: // Header size: 0x00000048 // Major runtime version: 0x0002 // Minor runtime version: 0x0005 // 0x00002110 [0x0000076c] address [size] of Metadata Directory: // Flags: 0x00000001 // Entry point token: 0x06000001 // 0x00000000 [0x00000000] address [size] of Resources Directory: // 0x00000000 [0x00000000] address [size] of Strong Name Signature: // 0x00000000 [0x00000000] address [size] of CodeManager Table: // 0x00000000 [0x00000000] address [size] of VTableFixups Directory: // 0x00000000 [0x00000000] address [size] of Export Address Table: // 0x00000000 [0x00000000] address [size] of Precompile Header: // Export Address Table Jumps: // No data. ... more stuff deleted here ... // 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 } Not a good solution for this client, especially they wanted to inspect a large number of files. Someone would need to open them all, dig around in the metadata, then note the assembly version manually. One could also write a utility to parse the output and extract the version info, but I was really hoping to find an easier route. DUMPBINNext up was DUMPBIN.EXE. If you run DUMPBIN against a file, and use the CLRHEADER switch it will tell you about any .NET headers and their versions inside an assembly. Good potential for batch file manipulation. Similar to ILDASM, it might offer some problems due to the output being fairly verbose and needing to be parsedC:\temp\>DUMPBIN C1.EXE /CLRHEADER
Microsoft (R) COFF/PE Dumper Version 8.00.50727.42
Copyright (C) Microsoft Corporation. All rights reserved.
Dump of file C1.EXE
File Type: EXECUTABLE IMAGE
clr Header:
48 cb
2.05 runtime version
206C [ 5D0] RVA [size] of MetaData Directory
1 flags
6000001 entry point token
0 [ 0] RVA [size] of Resources Directory
0 [ 0] RVA [size] of StrongNameSignature Directory
0 [ 0] RVA [size] of CodeManagerTable Directory
0 [ 0] RVA [size] of VTableFixups Directory
0 [ 0] RVA [size] of ExportAddressTableJumps Directory
0 [ 0] RVA [size] of ManagedNativeHeader Directory
Summary
2000 .reloc
2000 .rsrc
2000 .text
Custom CodeWith enough time and custom code, anything is possible! It always scares the Biztalk and Sharepoint sales guys when I say things like that.After some fruitless searching trying to find a utility to do the work for me as I wanted it, I gave up and decided to code a simple CLRVer utility. You pass CLRVer a filename. In ins console output CLRVer tells you if its a CLR file and what version of the CLR runtime it wants. You could conceivably pipe input to it or script it for large scale file investigations. Or you could use the source code for a variety of other means. A file explorer extension might be cool here. Another project, another day! To use the CLRVer utility you simply run CLRVER with the filename. In the sample below I run CLRVer against my 2.0 version of spacewar.exe, and against the xcopy.exe that comes with Windows, a native Win32 executable. Command line execution and output below. C:\dev\CLRVer\bin\Debug>clrver \dev\clrver\testfiles\spacewar.exe \dev\clrver\testfiles\spacewar.exe=v2.0.50727 C:\dev\CLRVer\bin\Debug>clrver \dev\clrver\testfiles\xcopy.exe \dev\clrver\testfiles\xcopy.exe=NotCLR
CLRVer offers up a variety of return values. The format is always [filename=][returnvalue]. Return values begining with a 'v' are clr files. All the return values are detailed below.
The source code for this application is surprisingly simple. Basically we load the assembly from the file and try and fine out the CLR version via the Assembly.ImageRuntimeVersion information. If its not a CLR assembly the Assembly.LoadFrom call will throw a System.BadImageFormatException. We can trap this exception and use it identify non-CLR files and unmanaged code. static void Main(string[] args)
{
try
{
string _fn = args[0];
_fn = _fn.Normalize();
if (args.Length < 1) { Console.WriteLine("0"); return;}
Console.Write(_fn); Console.Write("=");
if (!(System.IO.File.Exists(_fn))) {Console.WriteLine("-1"); return;}
Assembly a = Assembly.LoadFrom(_fn);
Console.WriteLine( a.ImageRuntimeVersion);
}
catch (System.BadImageFormatException ex){Console.WriteLine("NotCLR");}
catch (Exception ex){Console.WriteLine("-2");}
Scarily enough I spent more time searching for solutions than I did coding. Source code and binary may be found in CLRVer.zip on the DevFish.NET downloads page. Send feedback to jhealy@microsoft.com. Carpe diem.... >лл(o>... Building .NET developer communities in Florida / Alabama / Mississippi
|