Retrieve custom file version properties

I'm attempting to retireve custom version attributes from MS hotfix EXEs.  This is the info in the file properties on the "Version" tab in the "Other version information" (as seen on XP).  MS hotfixes includes additional version attributes here, e.g. "Support path".  I need to retrieve this information through my .NET app.  System.diags.FileVersionInfo allows me to retrieve the standards attributes for the files such as internal name name etc, but doesn't appear to expose custom attributes.

Currently using VB.NET 2005 and building for .NET 2.0.  Any assistance will be appreciated.
LVL 7
sj_hicksAsked:
Who is Participating?

Improve company productivity with a Business Account.Sign Up

x
 
Bob LearnedConnect With a Mentor Commented:
Here you go:
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;
 
public class FileVersionInfoEx
{
 
    [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")]
    private static unsafe 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")]
    private static unsafe extern bool VerQueryValue(byte[] pBlock,
         string pSubBlock, out short* pValue, out uint len);
 
    public static unsafe List<string> GetFileVersionInfo(string path, params string[] propertyList)
    {
        int handle = 0;
        int size = GetFileVersionInfoSize(path, out handle);
        short* subBlock = null;
 
        List<string> list = new List<string>();
 
        if (size != 0)
        {
            byte[] buffer = new byte[size];
 
            uint len = 0;
            if (GetFileVersionInfo(path, handle, size, buffer) &&
                VerQueryValue(buffer, @"\VarFileInfo\Translation", out subBlock, out len) && len > 2)
            {
                foreach (string property in propertyList)
                    list.Add(FindVersionValue(buffer, subBlock, property));
            }
        }
        return list;
    }
 
    /// <summary>
    /// Get the complete string table for the VS_VERSION_INFO, so that you can look for custom
    /// property names.
    /// </summary>
    public static unsafe string GetStringTable(string path)
    {
        int handle = 0;
        int size = GetFileVersionInfoSize(path, out handle);
        short* subBlock = null;
 
        List<string> list = new List<string>();
 
        if (size != 0)
        {
            byte[] buffer = new byte[size];
 
            uint len = 0;
            if (GetFileVersionInfo(path, handle, size, buffer) &&
                VerQueryValue(buffer, @"\VarFileInfo\Translation", out subBlock, out len) && len > 2)
            {
                return Encoding.Unicode.GetString(buffer).Replace("\0", "");
            }
        }
        return "";
    }
 
    private static unsafe string FindVersionValue(byte[] buffer, short* subBlock, string property)
    {
        string spv = @"\StringFileInfo\" + subBlock[0].ToString("X4") + subBlock[1].ToString("X4") + '\\' + property;
        byte* pVersion = null;
        string value;
        uint len = 0;
        if (VerQueryValue(buffer, spv, out value, out len))
            return value;
        return "";
    }
}

Open in new window

0
 
Bob LearnedCommented:
I have a custom C# class that can do the job, but the code is not translatable to VB.NET, since it uses unsafe pointers.  If you would like to see it, you could build a C# DLL, and then reference it in your VB.NET application.

Bob
0
 
sj_hicksAuthor Commented:
Bob, that'd be great, no problems working with a C# class and dll.  Can I take a look at it?
Thanks, Stephen.
0
 
Bob LearnedCommented:
Sample usage:

            Dim valueList As List(Of String) = FileVersionInfoEx.GetFileVersionInfo("C:\Downloads\WindowsXP-KB896256-v4-x86-ENU.exe",
                "Installer Engine", "Proc. Architecture", "Self-Extractor Version")

Bob
0
 
sj_hicksAuthor Commented:
Worked great.  Thanks Bob, you truly are The Learned One.
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.