Saturday, August 07, 2004

 

GetFileVersion in C#

FileVersion是我们经常需要用到的函数,根据Junfeng Zhang的指点,在C# 1.1以上版本mscoree.dll 中提供相应的 API GetFileVersion

from http://weblogs.asp.net/junfeng/archive/2004/02/06/68334.aspx

Another commonly asked question.

There are many ways to detect if a given file is a managed assembly or not. For example, in VS.Net 2002/2003, dumpbin has an option /clrheader. It will dump the CLR header for you if the file is a managed assembly. You can also run ildasm on the file. If it is not an assembly, it will complain.Other people suggest to inspect the PE header of the file.

What we are talking about here is API level detection.

First unmanaged API.

In .Net framework 1.1 mscoree.dll has an API GetFileVersion. Its definition is

STDAPI GetFileVersion(LPCWSTR szFilename, LPWSTR szBuffer, DWORD cchBuffer, DWORD* dwLength);

(参见:http://ftp.emini.dk/pub/php/win32/dev/php_build/dotnet/mscoree.h


Suzanne described what this API does here
http://blogs.gotdotnet.com/suzcook/commentview.aspx/48306e9f-df29-4ae1-8fe8-7bbdbffde140

[quote]
To get it programmatically, from managed code, use Assembly.ImageRuntimeVersion. From unmanaged, use mscoree.dll's GetFileVersion(). (From the command line, starting in v2.0, ildasm.exe will show it if you double-click on "MANIFEST" and look for "Metadata version".) Those will give you the CLR version that the image claims it wants. By default, it's the version that the image was compiled against. However, that's not necessarily what it will be, since compilers can be configured to put any string there.

Also, the CLR version that will be run by an exe is not necessarily the same as what is in its image runtime version. The chosen version can also depend on its hosting application's choice, a config file, environment variables, and registry settings. If you need to override those, you can set the supportedRuntime/requiredRuntime in the app.config for the process exe.
[/quote]

Basically it tells which runtime this assembly is built against. If the given file is not a managed assembly, this API returns 0x8007000B (ERROR_BAD_IMAGE).

Now managed API.

Assembly.LoadFrom will throw BadImageFormatException if the given file is not a managed assembly.

This exception could be thrown for other reason as well. Suzanne kindly points out a more robust way. Once you catch the BadImageFormatException, look at its HResult field. If HResult is COR_E_ASSEMBLYEXPECTED, it means this is not a managed assembly.

那么在C#中取得unmanaged file的version这么办呢?MSDN上面又一个例子

from http://msdn.microsoft.com/library/en-us/csref/html/vcwlkunsafecodetutorial.asp

Example 3
This example reads and displays the Win32 version number of the executable file, which is the same as the assembly version number in this example. The executable file, in this example, is printversion.exe. The example uses the Platform SDK functions VerQueryValue, GetFileVersionInfoSize, and GetFileVersionInfo to retrieve specified version information from the specified version-information resource.

This example uses pointers because it simplifies the use of methods whose signatures use pointers to pointers, which are common in the Win32 APIs.

// printversion.cs
// compile with: /unsafe
using System;
using System.Reflection;
using System.Runtime.InteropServices;

// Give this assembly a version number:
[assembly:AssemblyVersion("4.3.2.1")]

public class Win32Imports
{
[DllImport("version.dll")]
public static extern bool GetFileVersionInfo (string sFileName,
int handle, int size, byte[] infoBuffer);
[DllImport("version.dll")]
public static extern int GetFileVersionInfoSize (string sFileName,
out int handle);

// The third parameter - "out string pValue" - is automatically
// marshaled from ANSI to Unicode:
[DllImport("version.dll")]
unsafe public static extern bool VerQueryValue (byte[] pBlock,
string pSubBlock, out string pValue, out uint len);
// This VerQueryValue overload is marked with 'unsafe' because
// it uses a short*:
[DllImport("version.dll")]
unsafe public static extern bool VerQueryValue (byte[] pBlock,
string pSubBlock, out short *pValue, out uint len);
}

public class C
{
// Main is marked with 'unsafe' because it uses pointers:
unsafe public static int Main ()
{
try
{
int handle = 0;
// Figure out how much version info there is:
int size =
Win32Imports.GetFileVersionInfoSize("printversion.exe",
out handle);

if (size == 0) return -1;

byte[] buffer = new byte[size];

if (!Win32Imports.GetFileVersionInfo("printversion.exe", handle, size, buffer))
{
Console.WriteLine("Failed to query file version information.");
return 1;
}

short *subBlock = null;
uint len = 0;
// Get the locale info from the version info:
if (!Win32Imports.VerQueryValue (buffer, @"\VarFileInfo\Translation", out subBlock, out len))
{
Console.WriteLine("Failed to query version information.");
return 1;
}

string spv = @"\StringFileInfo\" + subBlock[0].ToString("X4") + subBlock[1].ToString("X4") + @"\ProductVersion";

byte *pVersion = null;
// Get the ProductVersion value for this program:
string versionInfo;

if (!Win32Imports.VerQueryValue (buffer, spv, out versionInfo, out len))
{
Console.WriteLine("Failed to query version information.");
return 1;
}

Console.WriteLine ("ProductVersion == {0}", versionInfo);
}
catch (Exception e)
{
Console.WriteLine ("Caught unexpected exception " + e.Message);
}

return 0;
}
}

Example Output
ProductVersion == 4.3.2.1

具体参考
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/resources/versioninformation/
versioninformationreference/versioninformationfunctions/verqueryvalue.asp

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/resources/versioninformation/
versioninformationreference/versioninformationfunctions/getfileversioninfosize.asp

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/resources/versioninformation/
versioninformationreference/versioninformationfunctions/getfileversioninfo.asp



<< Home

This page is powered by Blogger. Isn't yours?