1

I'm trying to find a way to get an Extended File Attribute (specifically, the "Product Version") on a COM DLL in C#. I found a few examples on MSDN on using the Shell32 from adding the "Microsoft Shell Controls and Automation" COM reference, but the documentation seems somewhat vague. Is there a simple way to do this?

For example: Take the following properties of C:\Windows\Notepad.exe:

Properties of Notepad.exe

I want to programatically get the "Product version" attribute in C#. By the way, this could be any file, however, I'm just using Notepad.exe because it's a generic example

Ryan
  • 1,300
  • 12
  • 29

3 Answers3

5

Alternatively, you can use the FileVersionInfo class to do that in a single line:

Console.WriteLine(FileVersionInfo.GetVersionInfo(@"C:\Windows\notepad.exe").ProductVersion);
vcsjones
  • 138,677
  • 31
  • 291
  • 286
  • Good answer, in fact this is probably a better solution than mine for what I'm trying to do, however, if you need to get other attributes, I don't think this will be enough. – Ryan Mar 27 '15 at 19:50
  • @Ryan, The FileVersionInfo class has probably all the properties you will ever need to get. Go have a look at it. https://msdn.microsoft.com/en-us/library/system.diagnostics.fileversioninfo(v=vs.110).aspx – jac Mar 27 '15 at 22:30
  • @vcsjones By the way, I forgot to thank you for posting this answer. It was all I really needed, without the extra complexity of adding a COM reference for the Shell32 stuff. I agree that the FileVersionInfo has many properties, however, there are certain cases (i.e. if I want to get the "Genre" attribute from an mp3) where I would need something more than FileVersionInfo. – Ryan Mar 27 '15 at 22:44
  • @ryan, yeah, if you need those attributes, Win32 is the best / only way. – vcsjones Mar 27 '15 at 22:46
2

I came up with the following easy to use function that will return the value of any file property:

 public static string GetExtendedFileAttribute(string filePath, string propertyName)
    {
        string retValue = null;
        Type shellAppType = Type.GetTypeFromProgID("Shell.Application");
        object shell = Activator.CreateInstance(shellAppType);
        Shell32.Folder folder = (Shell32.Folder)shellAppType.InvokeMember("NameSpace", System.Reflection.BindingFlags.InvokeMethod, null, shell, new object[] { @"C:\Windows\System32" });
        int? foundIdx = null;
        for (int i = 0; i < short.MaxValue; i++)
        {
            string header = folder.GetDetailsOf(null, i);
            if (header == propertyName)
            {
                foundIdx = i;
                break;
            }
        }

        if (foundIdx.HasValue)
        {
            foreach (FolderItem2 item in folder.Items())
            {
                if (item.Name.ToUpper() == System.IO.Path.GetFileName(filePath).ToUpper())
                {
                    retValue = folder.GetDetailsOf(item, foundIdx.GetValueOrDefault());
                    break;
                }
            }
        }


        return retValue;

    }

Here is an example of how it's called:

 static void Main(string[] args)
    {
        Console.WriteLine(GetExtendedFileAttribute(@"C:\Windows\Notepad.exe", "Product version"));   
        Console.ReadLine();
    }

Here is the output:

enter image description here

Ryan
  • 1,300
  • 12
  • 29
0

.NET has built-in methods to do this.

MessageBox.Show("Notepad product version " + GetProductVersion("C:\\Windows\\notepad.exe"), "Product Version");

public string GetProductVersion(string fileName)
{
    System.Diagnostics.FileVersionInfo fileVersionInfo =
        System.Diagnostics.FileVersionInfo.GetVersionInfo(fileName);
    return fileVersionInfo.ProductVersion;
}

Result

jac
  • 9,666
  • 2
  • 34
  • 63