3

I have a SFX(self-extracting executable) file in windows (Created with zip tools like 7z, WinRar, ....) with the following details:

File Details

I want to get CopyRight text in C#, So I wrote the following code:

var fileVersionInfo = FileVersionInfo.GetVersionInfo(filePath);
Console.Write(fileVersionInfo.LegalCopyright)

fileVersionInfo.LegalCopyright is always empty! What's the problem?

Edit:
My original Code:

var fileVersionInfo = FileVersionInfo.GetVersionInfo(filePath1);
var properties = typeof(FileVersionInfo).GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (var propertyInfo in properties)
{
    var value = propertyInfo.GetValue(fileVersionInfo);
    Console.WriteLine("{0} = {1}", propertyInfo.Name, value);
}
Console.ReadKey();

The result:

File Details

Mohammad Dayyan
  • 21,578
  • 41
  • 164
  • 232
  • FileVersionInfo does not have a bug. Review [this post](http://stackoverflow.com/a/23145471/17034). The most obvious mistake you could make here is to try to obtain the info for the SFX file instead of your own file. Or the other way around. – Hans Passant Jan 17 '17 at 09:33
  • add a `Console.Write(filePath)` to prove you're reading the correct file. are the other version info properties empty as well? – Cee McSharpface Jan 17 '17 at 09:41
  • 1
    I'm dead sure about `filePath`. Please see the edit section. – Mohammad Dayyan Jan 17 '17 at 10:35
  • the second screenshot shows that the file resides in the "Downloads" folder. is the file blocked (file > properties > unblock or similar, depending on Windows version)? – Cee McSharpface Jan 23 '17 at 14:01
  • @dlatikay: No it's not block. You can download and test it from here http://dl2.soft98.ir/soft/d/DriverEasy.Pro.5.1.6.18378.Portable.exe – Mohammad Dayyan Jan 24 '17 at 05:18
  • can now reproduce on my system. Windows shell, Visual Studio 2015 and Johnson's Resouce Hacker can read CompanyName, Author, LegalCopyright and ProductVersion just fine. Other properties of the VERSIONINFO struct in the non-compressed part are empty. The .NET runtime returns everything empty except part of versions, Language, and FileName. – Cee McSharpface Jan 24 '17 at 08:53
  • This http://stackoverflow.com/a/2234794/1132334 suggests that the OS language setting could influence the results. but that would mean that there are at least two different versioninfo structures in the binary, which I could not confirm for your .exe – Cee McSharpface Jan 24 '17 at 10:52
  • At the risk of contradicting @Hans Passant, we have a clear repro and think it is a bug [somewhere down here](https://referencesource.microsoft.com/#System/services/monitoring/system/diagnosticts/FileVersionInfo.cs,9266a01b8da320ff). At least in a sense that the .NET framework does not return the same results as the Windows shell and ResHacker and Visual Studio's executable viewer do. Path confusion, compression, password protection, download blocking have been ruled out. – Cee McSharpface Jan 26 '17 at 11:02

3 Answers3

5

(My reputation is too low to make a comment, so i post it here)

I have just tested the following code, and it works normally for me.

var fileVersionInfo = FileVersionInfo.GetVersionInfo(@"C:\Users\usr\Desktop\Game\steamIntegration\steam_api.dll");
Console.Write(fileVersionInfo.LegalCopyright);
Console.ReadLine();

Maybe your permissions are not sufficient enough for that file. Add a *.manifest to your project change the requestedExecutionLevel to:

<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />

Maybe that solves your problem.

Lars Crown
  • 216
  • 1
  • 5
  • 1
    this is more an answer than a comment already, so don't worry. maybe it has to do with the SFX file type, did you test only with a DLL, or with an SFX too? maybe shell can peek into the compressed format, and FileVersionInfo cannot? – Cee McSharpface Jan 17 '17 at 08:19
  • Ok i just downloaded 7-ZIP SFX Maker v3.3 to create a SFX by myself. I was still able to read the Copyright, even with invoker rights. – Lars Crown Jan 17 '17 at 08:33
  • Thanks for answer, I tested it, No change, `LegalCopyright` is still empty – Mohammad Dayyan Jan 17 '17 at 09:08
  • Can you tell me how or with what programm you created your SFX application? Did you test it already with the administrator rights? – Lars Crown Jan 17 '17 at 09:12
  • I tested it with admin, no change, File created with 7zip 9.22 with Password – Mohammad Dayyan Jan 17 '17 at 10:08
  • You can download and test it from http://dl2.soft98.ir/soft/d/DriverEasy.Pro.5.1.6.18378.Portable.exe – Mohammad Dayyan Jan 24 '17 at 05:19
  • there is a [hack in the framework](https://referencesource.microsoft.com/#System/services/monitoring/system/diagnosticts/FileVersionInfo.cs,9266a01b8da320ff) (starting at line 470, they call it "a few shots in dark") which may or may not be related. going to try to confirm that later. – Cee McSharpface Jan 24 '17 at 11:44
1

The behavior you observe is due to a shortcoming in the implementation of the private function GetVersionInfoForCodePage in line 411 of the Microsoft.NET framework class FileVersionInfo, currently in version 4.6.2 and likely much earlier:

// fileVersion is chosen based on best guess. Other fields can be used if appropriate. 
return (fileVersion != string.Empty);

This citation from reference source (comment theirs) means that the function will give up an otherwise correctly guessed codepage-specific version info, if its fileVersion member is empty (that of the block, not that in the header, which adds to the confusion).

This is the case with your exe file:

version info as ResHacker shows it

When we patch the framework to use this instead...

return (productVersion != string.Empty);

...it works as expected (tested in both console and Windows application):

output from patched version

So two options:

  1. Compile the exe so that its FileVersion does not end up empty. Hopefully it is not the fault of your compression tool to not transport this information.
  2. File a bug with Microsoft. What I gleaned from their reference source licence, it does not permit to include derived works in any product.
Cee McSharpface
  • 8,493
  • 3
  • 36
  • 77
1

Finally I could find a solution:
1. First install the following package:

Microsoft.WindowsAPICodePack.Shell

It has a dependency package, Nuget install it automatically Microsoft.WindowsAPICodePack.Core

2. Now we can get file properties as the following code

using System;
using System.Reflection;
using Microsoft.WindowsAPICodePack.Shell.PropertySystem;

namespace ConsoleApplication1
{
    internal class Program
    {
        private static void Main()
        {
            const string filePath1 = @"C:\Users\Mohammad\Downloads\Test\.....exe";
            var shellFile = Microsoft.WindowsAPICodePack.Shell.ShellObject.FromParsingName(filePath1);
            foreach (var propertyInfo in typeof(ShellProperties.PropertySystem).GetProperties(BindingFlags.Public | BindingFlags.Instance))
            {
                var shellProperty = propertyInfo.GetValue(shellFile.Properties.System, null) as IShellProperty;
                if (shellProperty?.ValueAsObject == null) continue;
                var shellPropertyValues = shellProperty.ValueAsObject as object[];
                if (shellPropertyValues != null && shellPropertyValues.Length > 0)
                {
                    foreach (var shellPropertyValue in shellPropertyValues)
                        Console.WriteLine("{0} = {1}", propertyInfo.Name, shellPropertyValue);
                }
                else
                    Console.WriteLine("{0} = {1}", propertyInfo.Name, shellProperty.ValueAsObject);
            }
            Console.ReadKey();
        }
    }
}
Mohammad Dayyan
  • 21,578
  • 41
  • 164
  • 232