Closed weshaggard closed 2 weeks ago
@weshaggard, the MetadataReader solution we have on Unix only allows us to inspect managed assemblies. I don't see how that could be used to make a compatible implementation on Windows, which needs to be able to inspect native Windows binaries.
I was under the impression from @nguerrera that the MetadaReader might also enable us to read the PE headers with the version info for non-managed as well but I'm not sure of the details. This work item can still be used to investigate the feasibility.
If that's feasible, great :)
It should be feasible though the info you need is not in the PE headers but in a Win32 resource of the PE file. The same resource is used for managed and native PE files. You can get to the PE section blob from the PEReader but then you'll have to parse the version resource yourself. See Roslyn's reader/writer for this format here: https://github.com/dotnet/roslyn/blob/master/src/Compilers/Core/Portable/CvtRes.cs
@weshaggard does this issue still have any traction, or should I close as abandoned?
I think this is still worth investigating.
Another benefit of doing it this way is that you aren't forced to have a file on disk, it becomes trivial to add an overload that takes a Stream. cc @jaredpar
At some point, somebody was working on this and I think there was an email thread with more details on how to proceed. I will try to dig it up.
Here's the old message that I sent to someone who was going to take a stab at this:
I think the following should get you the win32 resource blob:
using (FileStream stream = File.OpenRead(pathToAssembly))
using (var peReader = new PEReader(stream))
{
DirectoryEntry resourceDirectory = peReader.PEHeaders.PEHeader.ResourceTableDirectory;
PEMemoryBlock block = peReader.GetSectionData(resourceDirectory.RelativeVirtualAddress);
if (block.Length == 0)
{
// no win32 resources
}
if (resourceDirectory.Size > block.Length)
{
// corrupt file (bad directory entry)
}
var blobReader = new BlobReader(block.Pointer, resourceDirectory.Size);
From there you’ll want to reference some other code that reads it. https://github.com/Microsoft/cci/blob/c9cdc0e4852ff6a38a6e5057c90c41cc138b70a8/PEReaderAndWriter/PEReader/PEFileToObjectModel.cs#L675 is enumerating all of the win32 resources and Win32ResourceMemoryReader there is the equivalent to blobReader above.
You’ll want to do the same enumeration and look for the version resource, which has TypeId == 0x10.
From the RVAToData and Size of that resource, make another BlobReader just as we did from the resourceDirectory.RelativeVirtualAddress and resourceDirectory.Size.
Use the second blob reader to read the actual version resource as written by https://github.com/dotnet/roslyn/blob/c48bbec4f6b1ff3704c341b4e1eb928c19f288c1/src/Compilers/Core/Portable/CvtRes.cs
Related: https://github.com/dotnet/roslyn/issues/11386
We could put reading and writing API for this resource from a higher level than just blob into System.Reflection.Metadata and then use that API from FileVersionInfo and the compiler.
Due to lack of recent activity, this issue has been marked as a candidate for backlog cleanup. It will be closed if no further activity occurs within 14 more days. Any new comment (by anyone, not necessarily the author) will undo this process.
This process is part of our issue cleanup automation.
This issue will now be closed since it had been marked no-recent-activity
but received no further activity in the past 14 days. It is still possible to reopen or comment on the issue, but please note that the issue will be locked if it remains inactive for another 30 days.
Today we use PInvokes on Windows to implement System.Diagnostics.FileVersionInfo and we use MetadataReader for Unix. If we can do it compatibly we should make this a pure portable library and use the MetadataReader for all platforms and eliminate the need for the RID fork.