FileVersionInfo - getting the FileDescription in C#

Getting the file description in C# requires using the VerQueryInfo calls to load in the data from the file.  First you load in the culture information so you get the information in the right language and then you load the actual data into the buffer.  To do this you need to call a couple of external unsafe method calls to the various methods defined in version.dll

Below is a small class that takes in a path and gets the file version information from it.  This is useful when reading in the WPC logs to turn the application's run into an actual name for the application.

 

using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Runtime.InteropServices;

namespace OneCareService
{
    public class FileVersionInfo
    {
        [DllImport("version.dll")]
        private static extern bool GetFileVersionInfo(string sFileName,
             int handle, int size, byte[] infoBuffer);
        [DllImport("version.dll")]
        private 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 private 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 private static extern bool VerQueryValue(byte[] pBlock,
             string pSubBlock, out short* pValue, out uint len);

        public static unsafe string GetFileVersionNameInfo(string path)
        {
            string name = null;
            int handle = 0;
            int size = GetFileVersionInfoSize(path, out handle);
            if (size != 0)
            {
                byte[] buffer = new byte[size];

                if (GetFileVersionInfo(path, handle, size, buffer))
                {
                    uint len = 0;
                    short* subBlock = null;
                    if (VerQueryValue(buffer, @"\VarFileInfo\Translation", out subBlock, out len) && len > 2)
                    {
                        string spv = @"\StringFileInfo\" + subBlock[0].ToString("X4") + subBlock[1].ToString("X4") + @"\FileDescription";
                        byte* pVersion = null;
                        string versionInfo;
                        if (VerQueryValue(buffer, spv, out versionInfo, out len))
                        {
                            name = versionInfo;
                        }
                    }
                }
            }
            if (name == null)
            {
                name = Path.GetFileNameWithoutExtension(path);
            }
            return name;
        }
    }
}