Imported Upstream version 5.0.0.42

Former-commit-id: fd56571888259555122d8a0f58c68838229cea2b
This commit is contained in:
Xamarin Public Jenkins (auto-signing)
2017-04-10 11:41:01 +00:00
parent 1190d13a04
commit 6bdd276d05
19939 changed files with 3099680 additions and 93811 deletions

View File

@@ -0,0 +1,67 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.22609.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Diagnostics.FileVersionInfo", "src\System.Diagnostics.FileVersionInfo.csproj", "{00EDA5FD-E802-40D3-92D5-56C27612D36D}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{2D0715BD-01EA-4E9D-AC88-DA5410C15183}"
ProjectSection(SolutionItems) = preProject
..\.nuget\packages.Windows_NT.config = ..\.nuget\packages.Windows_NT.config
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Diagnostics.FileVersionInfo.Tests", "tests\System.Diagnostics.FileVersionInfo.Tests\System.Diagnostics.FileVersionInfo.Tests.csproj", "{6DFDB760-CC88-48AE-BD81-C64844EA3CBC}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Diagnostics.FileVersionInfo.TestAssembly", "tests\System.Diagnostics.FileVersionInfo.TestAssembly\System.Diagnostics.FileVersionInfo.TestAssembly.csproj", "{28EB14BE-3BC9-4543-ABA6-A932424DFBD0}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Unix_Debug|Any CPU = Unix_Debug|Any CPU
Unix_Release|Any CPU = Unix_Release|Any CPU
Release|Any CPU = Release|Any CPU
Windows_Debug|Any CPU = Windows_Debug|Any CPU
Windows_Release|Any CPU = Windows_Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{00EDA5FD-E802-40D3-92D5-56C27612D36D}.Debug|Any CPU.ActiveCfg = Windows_Debug|Any CPU
{00EDA5FD-E802-40D3-92D5-56C27612D36D}.Debug|Any CPU.Build.0 = Windows_Debug|Any CPU
{00EDA5FD-E802-40D3-92D5-56C27612D36D}.Unix_Debug|Any CPU.ActiveCfg = Unix_Debug|Any CPU
{00EDA5FD-E802-40D3-92D5-56C27612D36D}.Unix_Debug|Any CPU.Build.0 = Unix_Debug|Any CPU
{00EDA5FD-E802-40D3-92D5-56C27612D36D}.Unix_Release|Any CPU.ActiveCfg = Unix_Release|Any CPU
{00EDA5FD-E802-40D3-92D5-56C27612D36D}.Unix_Release|Any CPU.Build.0 = Unix_Release|Any CPU
{00EDA5FD-E802-40D3-92D5-56C27612D36D}.Release|Any CPU.ActiveCfg = Windows_Release|Any CPU
{00EDA5FD-E802-40D3-92D5-56C27612D36D}.Release|Any CPU.Build.0 = Windows_Release|Any CPU
{00EDA5FD-E802-40D3-92D5-56C27612D36D}.Windows_Debug|Any CPU.ActiveCfg = Windows_Debug|Any CPU
{00EDA5FD-E802-40D3-92D5-56C27612D36D}.Windows_Debug|Any CPU.Build.0 = Windows_Debug|Any CPU
{00EDA5FD-E802-40D3-92D5-56C27612D36D}.Windows_Release|Any CPU.ActiveCfg = Windows_Release|Any CPU
{00EDA5FD-E802-40D3-92D5-56C27612D36D}.Windows_Release|Any CPU.Build.0 = Windows_Release|Any CPU
{6DFDB760-CC88-48AE-BD81-C64844EA3CBC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6DFDB760-CC88-48AE-BD81-C64844EA3CBC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6DFDB760-CC88-48AE-BD81-C64844EA3CBC}.Unix_Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6DFDB760-CC88-48AE-BD81-C64844EA3CBC}.Unix_Debug|Any CPU.Build.0 = Debug|Any CPU
{6DFDB760-CC88-48AE-BD81-C64844EA3CBC}.Unix_Release|Any CPU.ActiveCfg = Release|Any CPU
{6DFDB760-CC88-48AE-BD81-C64844EA3CBC}.Unix_Release|Any CPU.Build.0 = Release|Any CPU
{6DFDB760-CC88-48AE-BD81-C64844EA3CBC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6DFDB760-CC88-48AE-BD81-C64844EA3CBC}.Release|Any CPU.Build.0 = Release|Any CPU
{6DFDB760-CC88-48AE-BD81-C64844EA3CBC}.Windows_Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6DFDB760-CC88-48AE-BD81-C64844EA3CBC}.Windows_Debug|Any CPU.Build.0 = Debug|Any CPU
{6DFDB760-CC88-48AE-BD81-C64844EA3CBC}.Windows_Release|Any CPU.ActiveCfg = Release|Any CPU
{6DFDB760-CC88-48AE-BD81-C64844EA3CBC}.Windows_Release|Any CPU.Build.0 = Release|Any CPU
{28EB14BE-3BC9-4543-ABA6-A932424DFBD0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{28EB14BE-3BC9-4543-ABA6-A932424DFBD0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{28EB14BE-3BC9-4543-ABA6-A932424DFBD0}.Unix_Debug|Any CPU.ActiveCfg = Debug|Any CPU
{28EB14BE-3BC9-4543-ABA6-A932424DFBD0}.Unix_Debug|Any CPU.Build.0 = Debug|Any CPU
{28EB14BE-3BC9-4543-ABA6-A932424DFBD0}.Unix_Release|Any CPU.ActiveCfg = Release|Any CPU
{28EB14BE-3BC9-4543-ABA6-A932424DFBD0}.Unix_Release|Any CPU.Build.0 = Release|Any CPU
{28EB14BE-3BC9-4543-ABA6-A932424DFBD0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{28EB14BE-3BC9-4543-ABA6-A932424DFBD0}.Release|Any CPU.Build.0 = Release|Any CPU
{28EB14BE-3BC9-4543-ABA6-A932424DFBD0}.Windows_Debug|Any CPU.ActiveCfg = Debug|Any CPU
{28EB14BE-3BC9-4543-ABA6-A932424DFBD0}.Windows_Debug|Any CPU.Build.0 = Debug|Any CPU
{28EB14BE-3BC9-4543-ABA6-A932424DFBD0}.Windows_Release|Any CPU.ActiveCfg = Release|Any CPU
{28EB14BE-3BC9-4543-ABA6-A932424DFBD0}.Windows_Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\dir.props" />
<PropertyGroup>
<AssemblyVersion>4.0.2.0</AssemblyVersion>
<IsNETCoreApp>true</IsNETCoreApp>
</PropertyGroup>
</Project>

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<BuildConfigurations>
netcoreapp;
uap;
</BuildConfigurations>
</PropertyGroup>
</Project>

View File

@@ -0,0 +1,44 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
// ------------------------------------------------------------------------------
// Changes to this file must follow the http://aka.ms/api-review process.
// ------------------------------------------------------------------------------
namespace System.Diagnostics
{
public sealed partial class FileVersionInfo
{
internal FileVersionInfo() { }
public string Comments { get { throw null; } }
public string CompanyName { get { throw null; } }
public int FileBuildPart { get { throw null; } }
public string FileDescription { get { throw null; } }
public int FileMajorPart { get { throw null; } }
public int FileMinorPart { get { throw null; } }
public string FileName { get { throw null; } }
public int FilePrivatePart { get { throw null; } }
public string FileVersion { get { throw null; } }
public string InternalName { get { throw null; } }
public bool IsDebug { get { throw null; } }
public bool IsPatched { get { throw null; } }
public bool IsPreRelease { get { throw null; } }
public bool IsPrivateBuild { get { throw null; } }
public bool IsSpecialBuild { get { throw null; } }
public string Language { get { throw null; } }
public string LegalCopyright { get { throw null; } }
public string LegalTrademarks { get { throw null; } }
public string OriginalFilename { get { throw null; } }
public string PrivateBuild { get { throw null; } }
public int ProductBuildPart { get { throw null; } }
public int ProductMajorPart { get { throw null; } }
public int ProductMinorPart { get { throw null; } }
public string ProductName { get { throw null; } }
public int ProductPrivatePart { get { throw null; } }
public string ProductVersion { get { throw null; } }
public string SpecialBuild { get { throw null; } }
public static System.Diagnostics.FileVersionInfo GetVersionInfo(string fileName) { throw null; }
public override string ToString() { throw null; }
}
}

View File

@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uap-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uap-Release|AnyCPU'" />
<ItemGroup>
<Compile Include="System.Diagnostics.FileVersionInfo.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\System.Runtime\ref\System.Runtime.csproj" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
</Project>

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<BuildConfigurations>
netcore50-Windows_NT;
net46-Windows_NT;
netcoreapp-Unix;
netcoreapp-Windows_NT;
</BuildConfigurations>
</PropertyGroup>
</Project>

View File

@@ -0,0 +1,70 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Build">
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
<PropertyGroup>
<ProjectGuid>{00EDA5FD-E802-40D3-92D5-56C27612D36D}</ProjectGuid>
<AssemblyName>System.Diagnostics.FileVersionInfo</AssemblyName>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<IsPartialFacadeAssembly Condition="'$(TargetGroup)' == 'net46'">true</IsPartialFacadeAssembly>
</PropertyGroup>
<!-- Help VS understand available configurations -->
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='netcore50-Windows_NT-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='netcore50-Windows_NT-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='net46-Windows_NT-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='net46-Windows_NT-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='netcoreapp-Unix-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='netcoreapp-Unix-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='netcoreapp-Windows_NT-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='netcoreapp-Windows_NT-Release|AnyCPU'" />
<ItemGroup Condition="'$(TargetGroup)' == 'netcore50' or '$(TargetGroup)' == 'netcoreapp'">
<Compile Include="System\Diagnostics\FileVersionInfo.cs" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetsWindows)' == 'true' And '$(TargetGroup)' == 'netcoreapp'">
<Compile Include="System\Diagnostics\FileVersionInfo.Windows.cs" />
<Compile Include="$(CommonPath)\Interop\Windows\Interop.Libraries.cs">
<Link>Common\Interop\Windows\Interop.Libraries.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\Interop\Windows\version\Interop.FileVersionInfo.cs">
<Link>Common\Interop\Windows\Interop.FileVersionInfo.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\Interop\Windows\version\Interop.FileVersionInfoType.cs">
<Link>Common\Interop\Windows\Interop.FileVersionInfoType.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\Interop\Windows\version\Interop.GetFileVersionInfoEx.cs">
<Link>Common\Interop\Windows\Interop.GetFileVersionInfoEx.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\Interop\Windows\version\Interop.GetFileVersionInfoSizeEx.cs">
<Link>Common\Interop\Windows\Interop.GetFileVersionInfoSizeEx.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\Interop\Windows\kernel32\Interop.VerLanguageName.cs">
<Link>Common\Interop\Windows\Interop.VerLanguageName.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\Interop\Windows\version\Interop.VerQueryValue.cs">
<Link>Common\Interop\Windows\Interop.VerQueryValue.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\Interop\Windows\version\Interop.VSFixedFileInfo.cs">
<Link>Common\Interop\Windows\Interop.VSFixedFileInfo.cs</Link>
</Compile>
</ItemGroup>
<ItemGroup Condition="('$(TargetsUnix)' == 'true' And '$(TargetGroup)' == 'netcoreapp') OR '$(TargetGroup)' == 'netcore50'">
<Compile Include="System\Diagnostics\FileVersionInfo.Metadata.cs" />
</ItemGroup>
<ItemGroup Condition="'$(TargetGroup)' == 'net46'">
<TargetingPackReference Include="mscorlib" />
<TargetingPackReference Include="System" />
</ItemGroup>
<ItemGroup>
<Reference Include="System.Diagnostics.Tools" />
<Reference Include="System.Globalization" />
<Reference Include="System.IO.FileSystem" />
<Reference Include="System.Runtime" />
<Reference Include="System.Runtime.InteropServices" />
</ItemGroup>
<ItemGroup Condition="'$(TargetsUnix)' == 'true'">
<ProjectReference Include="../../System.Reflection.Metadata/src/System.Reflection.Metadata.csproj" />
<Reference Include="System.Collections.Immutable" />
<Reference Include="System.IO" />
<Reference Include="System.Runtime.Extensions" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
</Project>

View File

@@ -0,0 +1,309 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
using System.IO;
using System.Reflection.Metadata;
using System.Reflection.PortableExecutable;
namespace System.Diagnostics
{
public sealed partial class FileVersionInfo
{
private static readonly char[] s_versionSeparators = new char[] { '.' };
private FileVersionInfo(string fileName)
{
_fileName = fileName;
// For managed assemblies, read the file version information from the assembly's metadata.
// This isn't quite what's done on Windows, which uses the Win32 GetFileVersionInfo to read
// the Win32 resource information from the file, and the managed compiler uses these attributes
// to fill in that resource information when compiling the assembly. It's possible
// that after compilation, someone could have modified the resource information such that it
// no longer matches what was or wasn't in the assembly. But that's a rare enough case
// that this should match for all intents and purposes. If this ever becomes a problem,
// we can implement a full-fledged Win32 resource parser; that would also enable support
// for native Win32 PE files on Unix, but that should also be an extremely rare case.
if (!TryLoadManagedAssemblyMetadata())
{
// We could try to parse Executable and Linkable Format (ELF) files, but at present
// for executables they don't store version information, which is typically just
// available in the filename itself. For now, we won't do anything special, but
// we can add more cases here as we find need and opportunity.
}
}
// -----------------------------
// ---- PAL layer ends here ----
// -----------------------------
/// <summary>Attempt to load our fields from the metadata of the file, if it's a managed assembly.</summary>
/// <returns>true if the file is a managed assembly; otherwise, false.</returns>
private bool TryLoadManagedAssemblyMetadata()
{
try
{
// Try to load the file using the managed metadata reader
using (FileStream assemblyStream = new FileStream(_fileName, FileMode.Open, FileAccess.Read, FileShare.Read, bufferSize: 0x1000, useAsync: false))
using (PEReader peReader = new PEReader(assemblyStream))
{
if (peReader.HasMetadata)
{
MetadataReader metadataReader = peReader.GetMetadataReader();
if (metadataReader.IsAssembly)
{
LoadManagedAssemblyMetadata(metadataReader);
return true;
}
}
}
}
catch (BadImageFormatException) { }
return false;
}
/// <summary>Load our fields from the metadata of the file as represented by the provided metadata reader.</summary>
/// <param name="metadataReader">The metadata reader for the CLI file this represents.</param>
private void LoadManagedAssemblyMetadata(MetadataReader metadataReader)
{
AssemblyDefinition assemblyDefinition = metadataReader.GetAssemblyDefinition();
// Set the internal and original names based on the file name.
_internalName = _originalFilename = Path.GetFileName(_fileName);
// Set the product version based on the assembly's version (this may be overwritten
// later in the method).
Version productVersion = assemblyDefinition.Version;
_productVersion = productVersion.ToString();
_productMajor = productVersion.Major;
_productMinor = productVersion.Minor;
_productBuild = productVersion.Build != -1 ? productVersion.Build : 0;
_productPrivate = productVersion.Revision != -1 ? productVersion.Revision : 0;
// "Language Neutral" is used on Win32 for unknown language identifiers.
_language = "Language Neutral";
// Set other fields to default values in case they're not overwritten by attributes
_companyName = string.Empty;
_comments = string.Empty;
_fileDescription = " "; // this is what the managed compiler outputs when value isn't set
_fileVersion = string.Empty;
_legalCopyright = " "; // this is what the managed compiler outputs when value isn't set
_legalTrademarks = string.Empty;
_productName = string.Empty;
_privateBuild = string.Empty;
_specialBuild = string.Empty;
// Be explicit about initialization to suppress warning about fields not being set
_isDebug = false;
_isPatched = false;
_isPreRelease = false;
_isPrivateBuild = false;
_isSpecialBuild = false;
bool sawAssemblyInformationalVersionAttribute = false;
// Everything else is parsed from assembly attributes
MetadataStringComparer comparer = metadataReader.StringComparer;
foreach (CustomAttributeHandle attrHandle in assemblyDefinition.GetCustomAttributes())
{
CustomAttribute attr = metadataReader.GetCustomAttribute(attrHandle);
StringHandle typeNamespaceHandle = default(StringHandle), typeNameHandle = default(StringHandle);
if (TryGetAttributeName(metadataReader, attr, out typeNamespaceHandle, out typeNameHandle) &&
comparer.Equals(typeNamespaceHandle, "System.Reflection"))
{
if (comparer.Equals(typeNameHandle, "AssemblyCompanyAttribute"))
{
GetStringAttributeArgumentValue(metadataReader, attr, ref _companyName);
}
else if (comparer.Equals(typeNameHandle, "AssemblyCopyrightAttribute"))
{
GetStringAttributeArgumentValue(metadataReader, attr, ref _legalCopyright);
}
else if (comparer.Equals(typeNameHandle, "AssemblyDescriptionAttribute"))
{
GetStringAttributeArgumentValue(metadataReader, attr, ref _comments);
}
else if (comparer.Equals(typeNameHandle, "AssemblyFileVersionAttribute"))
{
GetStringAttributeArgumentValue(metadataReader, attr, ref _fileVersion);
ParseVersion(_fileVersion, out _fileMajor, out _fileMinor, out _fileBuild, out _filePrivate);
}
else if (comparer.Equals(typeNameHandle, "AssemblyInformationalVersionAttribute"))
{
GetStringAttributeArgumentValue(metadataReader, attr, ref _productVersion);
ParseVersion(_productVersion, out _productMajor, out _productMinor, out _productBuild, out _productPrivate);
sawAssemblyInformationalVersionAttribute = true;
}
else if (comparer.Equals(typeNameHandle, "AssemblyProductAttribute"))
{
GetStringAttributeArgumentValue(metadataReader, attr, ref _productName);
}
else if (comparer.Equals(typeNameHandle, "AssemblyTrademarkAttribute"))
{
GetStringAttributeArgumentValue(metadataReader, attr, ref _legalTrademarks);
}
else if (comparer.Equals(typeNameHandle, "AssemblyTitleAttribute"))
{
GetStringAttributeArgumentValue(metadataReader, attr, ref _fileDescription);
}
}
}
// When the managed compiler sees an [AssemblyVersion(...)] attribute, it uses that to set
// both the assembly version and the product version in the Win32 resources. If it doesn't
// see an [AssemblyVersion(...)], then it sets the assembly version to 0.0.0.0, however it
// sets the product version in the Win32 resources to whatever was defined in the
// [AssemblyFileVersionAttribute(...)] if there was one (unless there is an AssemblyInformationalVersionAttribute,
// in which case it always uses that for the product version). Without parsing the Win32 resources,
// we can't differentiate these two cases, so given the rarity of explicitly setting an
// assembly's version number to 0.0.0.0, we assume that if it is 0.0.0.0 then the attribute
// wasn't specified and we use the file version.
if (!sawAssemblyInformationalVersionAttribute && _productVersion == "0.0.0.0")
{
_productVersion = _fileVersion;
_productMajor = _fileMajor;
_productMinor = _fileMinor;
_productBuild = _fileBuild;
_productPrivate = _filePrivate;
}
}
/// <summary>Parses the version into its constituent parts.</summary>
private static void ParseVersion(string versionString, out int major, out int minor, out int build, out int priv)
{
// Relatively-forgiving parsing of a version:
// - If there are more than four parts (separated by periods), all results are deemed 0
// - If any part fails to parse completely as an integer, no further parts are parsed and are left as 0.
// - If any part partially parses as an integer, that value is used for that part.
// - Whitespace is treated like any other non-digit character and thus isn't ignored.
// - Each component is parsed as a ushort, allowing for overflow.
string[] parts = versionString.Split(s_versionSeparators);
major = minor = build = priv = 0;
if (parts.Length <= 4)
{
bool endedEarly;
if (parts.Length > 0)
{
major = ParseUInt16UntilNonDigit(parts[0], out endedEarly);
if (!endedEarly && parts.Length > 1)
{
minor = ParseUInt16UntilNonDigit(parts[1], out endedEarly);
if (!endedEarly && parts.Length > 2)
{
build = ParseUInt16UntilNonDigit(parts[2], out endedEarly);
if (!endedEarly && parts.Length > 3)
{
priv = ParseUInt16UntilNonDigit(parts[3], out endedEarly);
}
}
}
}
}
}
/// <summary>Parses a string as a UInt16 until it hits a non-digit.</summary>
/// <param name="s">The string to parse.</param>
/// <returns>The parsed value.</returns>
private static ushort ParseUInt16UntilNonDigit(string s, out bool endedEarly)
{
endedEarly = false;
ushort result = 0;
for (int index = 0; index < s.Length; index++)
{
char c = s[index];
if (c < '0' || c > '9')
{
endedEarly = true;
break;
}
result = (ushort)((result * 10) + (c - '0')); // explicitly allow for overflow, as this is the behavior employed on Windows
}
return result;
}
/// <summary>Gets the name of an attribute.</summary>
/// <param name="reader">The metadata reader.</param>
/// <param name="attr">The attribute.</param>
/// <param name="typeNamespaceHandle">The namespace of the attribute.</param>
/// <param name="typeNameHandle">The name of the attribute.</param>
/// <returns>true if the name could be retrieved; otherwise, false.</returns>
private static bool TryGetAttributeName(MetadataReader reader, CustomAttribute attr, out StringHandle typeNamespaceHandle, out StringHandle typeNameHandle)
{
EntityHandle ctorHandle = attr.Constructor;
switch (ctorHandle.Kind)
{
case HandleKind.MemberReference:
EntityHandle container = reader.GetMemberReference((MemberReferenceHandle)ctorHandle).Parent;
if (container.Kind == HandleKind.TypeReference)
{
TypeReference tr = reader.GetTypeReference((TypeReferenceHandle)container);
typeNamespaceHandle = tr.Namespace;
typeNameHandle = tr.Name;
return true;
}
break;
case HandleKind.MethodDefinition:
MethodDefinition md = reader.GetMethodDefinition((MethodDefinitionHandle)ctorHandle);
TypeDefinition td = reader.GetTypeDefinition(md.GetDeclaringType());
typeNamespaceHandle = td.Namespace;
typeNameHandle = td.Name;
return true;
}
// Unusual case, potentially invalid IL
typeNamespaceHandle = default(StringHandle);
typeNameHandle = default(StringHandle);
return false;
}
/// <summary>Gets the string argument value of an attribute with a single fixed string argument.</summary>
/// <param name="reader">The metadata reader.</param>
/// <param name="attr">The attribute.</param>
/// <param name="value">The value parsed from the attribute, if it could be retrieved; otherwise, the value is left unmodified.</param>
private static void GetStringAttributeArgumentValue(MetadataReader reader, CustomAttribute attr, ref string value)
{
EntityHandle ctorHandle = attr.Constructor;
BlobHandle signature;
switch (ctorHandle.Kind)
{
case HandleKind.MemberReference:
signature = reader.GetMemberReference((MemberReferenceHandle)ctorHandle).Signature;
break;
case HandleKind.MethodDefinition:
signature = reader.GetMethodDefinition((MethodDefinitionHandle)ctorHandle).Signature;
break;
default:
// Unusual case, potentially invalid IL
return;
}
BlobReader signatureReader = reader.GetBlobReader(signature);
BlobReader valueReader = reader.GetBlobReader(attr.Value);
const ushort Prolog = 1; // two-byte "prolog" defined by ECMA-335 (II.23.3) to be at the beginning of attribute value blobs
if (valueReader.ReadUInt16() == Prolog)
{
SignatureHeader header = signatureReader.ReadSignatureHeader();
int parameterCount;
if (header.Kind == SignatureKind.Method && // attr ctor must be a method
!header.IsGeneric && // attr ctor must be non-generic
signatureReader.TryReadCompressedInteger(out parameterCount) && // read parameter count
parameterCount == 1 && // attr ctor must have 1 parameter
signatureReader.ReadSignatureTypeCode() == SignatureTypeCode.Void && // attr ctor return type must be void
signatureReader.ReadSignatureTypeCode() == SignatureTypeCode.String) // attr ctor first parameter must be string
{
value = valueReader.ReadSerializedString();
}
}
}
}
}

View File

@@ -0,0 +1,181 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Globalization;
using System.Runtime.InteropServices;
using System.Text;
namespace System.Diagnostics
{
public sealed partial class FileVersionInfo
{
private unsafe FileVersionInfo(string fileName)
{
_fileName = fileName;
uint handle; // This variable is not used, but we need an out variable.
uint infoSize = Interop.Version.GetFileVersionInfoSizeEx(
(uint)Interop.Version.FileVersionInfoType.FILE_VER_GET_LOCALISED, _fileName, out handle);
if (infoSize != 0)
{
byte[] mem = new byte[infoSize];
fixed (byte* memPtr = mem)
{
IntPtr memIntPtr = new IntPtr((void*)memPtr);
if (Interop.Version.GetFileVersionInfoEx(
(uint)Interop.Version.FileVersionInfoType.FILE_VER_GET_LOCALISED | (uint)Interop.Version.FileVersionInfoType.FILE_VER_GET_NEUTRAL,
_fileName,
0U,
infoSize,
memIntPtr))
{
uint langid = GetVarEntry(memIntPtr);
if (!GetVersionInfoForCodePage(memIntPtr, ConvertTo8DigitHex(langid)))
{
// Some DLLs might not contain correct codepage information. In these cases we will fail during lookup.
// Explorer will take a few shots in dark by trying several specific lang-codepages
// (Explorer also randomly guesses 041D04B0=Swedish+CP_UNICODE and 040704B0=German+CP_UNICODE sometimes).
// We will try to simulate similar behavior here.
foreach (uint id in s_fallbackLanguageCodePages)
{
if (id != langid)
{
if (GetVersionInfoForCodePage(memIntPtr, ConvertTo8DigitHex(id)))
{
break;
}
}
}
}
}
}
}
}
// -----------------------------
// ---- PAL layer ends here ----
// -----------------------------
// Some dlls might not contain correct codepage information,
// in which case the lookup will fail. Explorer will take
// a few shots in dark. We'll simulate similar behavior by
// falling back to the following lang-codepages:
private static readonly uint[] s_fallbackLanguageCodePages = new uint[]
{
0x040904B0, // US English + CP_UNICODE
0x040904E4, // US English + CP_USASCII
0x04090000 // US English + unknown codepage
};
private static string ConvertTo8DigitHex(uint value)
{
return value.ToString("X8", CultureInfo.InvariantCulture);
}
private static Interop.Version.VS_FIXEDFILEINFO GetFixedFileInfo(IntPtr memPtr)
{
IntPtr memRef = IntPtr.Zero;
uint memLen;
if (Interop.Version.VerQueryValue(memPtr, "\\", out memRef, out memLen))
{
return (Interop.Version.VS_FIXEDFILEINFO)Marshal.PtrToStructure<Interop.Version.VS_FIXEDFILEINFO>(memRef);
}
return new Interop.Version.VS_FIXEDFILEINFO();
}
private static string GetFileVersionLanguage(IntPtr memPtr)
{
uint langid = GetVarEntry(memPtr) >> 16;
var lang = new StringBuilder(256);
Interop.Kernel32.VerLanguageName(langid, lang, (uint)lang.Capacity);
return lang.ToString();
}
private static string GetFileVersionString(IntPtr memPtr, string name)
{
IntPtr memRef = IntPtr.Zero;
uint memLen;
if (Interop.Version.VerQueryValue(memPtr, name, out memRef, out memLen))
{
if (memRef != IntPtr.Zero)
{
return Marshal.PtrToStringUni(memRef);
}
}
return string.Empty;
}
private static uint GetVarEntry(IntPtr memPtr)
{
IntPtr memRef = IntPtr.Zero;
uint memLen;
if (Interop.Version.VerQueryValue(memPtr, "\\VarFileInfo\\Translation", out memRef, out memLen))
{
return (uint)((Marshal.ReadInt16(memRef) << 16) + Marshal.ReadInt16((IntPtr)((long)memRef + 2)));
}
return 0x040904E4;
}
//
// This function tries to find version information for a specific codepage.
// Returns true when version information is found.
//
private bool GetVersionInfoForCodePage(IntPtr memIntPtr, string codepage)
{
string template = "\\\\StringFileInfo\\\\{0}\\\\{1}";
_companyName = GetFileVersionString(memIntPtr, string.Format(CultureInfo.InvariantCulture, template, codepage, "CompanyName"));
_fileDescription = GetFileVersionString(memIntPtr, string.Format(CultureInfo.InvariantCulture, template, codepage, "FileDescription"));
_fileVersion = GetFileVersionString(memIntPtr, string.Format(CultureInfo.InvariantCulture, template, codepage, "FileVersion"));
_internalName = GetFileVersionString(memIntPtr, string.Format(CultureInfo.InvariantCulture, template, codepage, "InternalName"));
_legalCopyright = GetFileVersionString(memIntPtr, string.Format(CultureInfo.InvariantCulture, template, codepage, "LegalCopyright"));
_originalFilename = GetFileVersionString(memIntPtr, string.Format(CultureInfo.InvariantCulture, template, codepage, "OriginalFilename"));
_productName = GetFileVersionString(memIntPtr, string.Format(CultureInfo.InvariantCulture, template, codepage, "ProductName"));
_productVersion = GetFileVersionString(memIntPtr, string.Format(CultureInfo.InvariantCulture, template, codepage, "ProductVersion"));
_comments = GetFileVersionString(memIntPtr, string.Format(CultureInfo.InvariantCulture, template, codepage, "Comments"));
_legalTrademarks = GetFileVersionString(memIntPtr, string.Format(CultureInfo.InvariantCulture, template, codepage, "LegalTrademarks"));
_privateBuild = GetFileVersionString(memIntPtr, string.Format(CultureInfo.InvariantCulture, template, codepage, "PrivateBuild"));
_specialBuild = GetFileVersionString(memIntPtr, string.Format(CultureInfo.InvariantCulture, template, codepage, "SpecialBuild"));
_language = GetFileVersionLanguage(memIntPtr);
Interop.Version.VS_FIXEDFILEINFO ffi = GetFixedFileInfo(memIntPtr);
_fileMajor = (int)HIWORD(ffi.dwFileVersionMS);
_fileMinor = (int)LOWORD(ffi.dwFileVersionMS);
_fileBuild = (int)HIWORD(ffi.dwFileVersionLS);
_filePrivate = (int)LOWORD(ffi.dwFileVersionLS);
_productMajor = (int)HIWORD(ffi.dwProductVersionMS);
_productMinor = (int)LOWORD(ffi.dwProductVersionMS);
_productBuild = (int)HIWORD(ffi.dwProductVersionLS);
_productPrivate = (int)LOWORD(ffi.dwProductVersionLS);
_isDebug = (ffi.dwFileFlags & (uint)Interop.Version.FileVersionInfo.VS_FF_DEBUG) != 0;
_isPatched = (ffi.dwFileFlags & (uint)Interop.Version.FileVersionInfo.VS_FF_PATCHED) != 0;
_isPrivateBuild = (ffi.dwFileFlags & (uint)Interop.Version.FileVersionInfo.VS_FF_PRIVATEBUILD) != 0;
_isPreRelease = (ffi.dwFileFlags & (uint)Interop.Version.FileVersionInfo.VS_FF_PRERELEASE) != 0;
_isSpecialBuild = (ffi.dwFileFlags & (uint)Interop.Version.FileVersionInfo.VS_FF_SPECIALBUILD) != 0;
// fileVersion is chosen based on best guess. Other fields can be used if appropriate.
return (_fileVersion != string.Empty);
}
private static uint HIWORD(uint dword)
{
return (dword >> 16) & 0xffff;
}
private static uint LOWORD(uint dword)
{
return dword & 0xffff;
}
}
}

View File

@@ -0,0 +1,303 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.IO;
using System.Text;
namespace System.Diagnostics
{
/// <summary>
/// Provides version information for a physical file on disk.
/// </summary>
public sealed partial class FileVersionInfo
{
private readonly string _fileName;
private string _companyName;
private string _fileDescription;
private string _fileVersion;
private string _internalName;
private string _legalCopyright;
private string _originalFilename;
private string _productName;
private string _productVersion;
private string _comments;
private string _legalTrademarks;
private string _privateBuild;
private string _specialBuild;
private string _language;
private int _fileMajor;
private int _fileMinor;
private int _fileBuild;
private int _filePrivate;
private int _productMajor;
private int _productMinor;
private int _productBuild;
private int _productPrivate;
private bool _isDebug;
private bool _isPatched;
private bool _isPrivateBuild;
private bool _isPreRelease;
private bool _isSpecialBuild;
/// <summary>
/// Gets the comments associated with the file.
/// </summary>
public string Comments
{
get { return _comments; }
}
/// <summary>
/// Gets the name of the company that produced the file.
/// </summary>
public string CompanyName
{
get { return _companyName; }
}
/// <summary>
/// Gets the build number of the file.
/// </summary>
public int FileBuildPart
{
get { return _fileBuild; }
}
/// <summary>
/// Gets the description of the file.
/// </summary>
public string FileDescription
{
get { return _fileDescription; }
}
/// <summary>
/// Gets the major part of the version number.
/// </summary>
public int FileMajorPart
{
get { return _fileMajor; }
}
/// <summary>
/// Gets the minor part of the version number of the file.
/// </summary>
public int FileMinorPart
{
get { return _fileMinor; }
}
/// <summary>
/// Gets the name of the file that this instance of <see cref="FileVersionInfo" /> describes.
/// </summary>
public string FileName
{
get { return _fileName; }
}
/// <summary>
/// Gets the file private part number.
/// </summary>
public int FilePrivatePart
{
get { return _filePrivate; }
}
/// <summary>
/// Gets the file version number.
/// </summary>
public string FileVersion
{
get { return _fileVersion; }
}
/// <summary>
/// Gets the internal name of the file, if one exists.
/// </summary>
public string InternalName
{
get { return _internalName; }
}
/// <summary>
/// Gets a value that specifies whether the file contains debugging information
/// or is compiled with debugging features enabled.
/// </summary>
public bool IsDebug
{
get { return _isDebug; }
}
/// <summary>
/// Gets a value that specifies whether the file has been modified and is not identical to
/// the original shipping file of the same version number.
/// </summary>
public bool IsPatched
{
get { return _isPatched; }
}
/// <summary>
/// Gets a value that specifies whether the file was built using standard release procedures.
/// </summary>
public bool IsPrivateBuild
{
get { return _isPrivateBuild; }
}
/// <summary>
/// Gets a value that specifies whether the file
/// is a development version, rather than a commercially released product.
/// </summary>
public bool IsPreRelease
{
get { return _isPreRelease; }
}
/// <summary>
/// Gets a value that specifies whether the file is a special build.
/// </summary>
public bool IsSpecialBuild
{
get { return _isSpecialBuild; }
}
/// <summary>
/// Gets the default language string for the version info block.
/// </summary>
public string Language
{
get { return _language; }
}
/// <summary>
/// Gets all copyright notices that apply to the specified file.
/// </summary>
public string LegalCopyright
{
get { return _legalCopyright; }
}
/// <summary>
/// Gets the trademarks and registered trademarks that apply to the file.
/// </summary>
public string LegalTrademarks
{
get { return _legalTrademarks; }
}
/// <summary>
/// Gets the name the file was created with.
/// </summary>
public string OriginalFilename
{
get { return _originalFilename; }
}
/// <summary>
/// Gets information about a private version of the file.
/// </summary>
public string PrivateBuild
{
get { return _privateBuild; }
}
/// <summary>
/// Gets the build number of the product this file is associated with.
/// </summary>
public int ProductBuildPart
{
get { return _productBuild; }
}
/// <summary>
/// Gets the major part of the version number for the product this file is associated with.
/// </summary>
public int ProductMajorPart
{
get { return _productMajor; }
}
/// <summary>
/// Gets the minor part of the version number for the product the file is associated with.
/// </summary>
public int ProductMinorPart
{
get { return _productMinor; }
}
/// <summary>
/// Gets the name of the product this file is distributed with.
/// </summary>
public string ProductName
{
get { return _productName; }
}
/// <summary>
/// Gets the private part number of the product this file is associated with.
/// </summary>
public int ProductPrivatePart
{
get { return _productPrivate; }
}
/// <summary>
/// Gets the version of the product this file is distributed with.
/// </summary>
public string ProductVersion
{
get { return _productVersion; }
}
/// <summary>
/// Gets the special build information for the file.
/// </summary>
public string SpecialBuild
{
get { return _specialBuild; }
}
/// <summary>
/// Returns a <see cref="FileVersionInfo" /> representing the version information associated with the specified file.
/// </summary>
public static FileVersionInfo GetVersionInfo(string fileName)
{
// Check for the existence of the file. File.Exists returns false if Read permission is denied.
if (!File.Exists(fileName))
{
throw new FileNotFoundException(fileName);
}
return new FileVersionInfo(fileName);
}
/// <summary>
/// Returns a partial list of properties in <see cref="FileVersionInfo" />
/// and their values.
/// </summary>
public override string ToString()
{
// An initial capacity of 512 was chosen because it is large enough to cover
// the size of the static strings with enough capacity left over to cover
// average length property values.
var sb = new StringBuilder(512);
sb.Append("File: ").AppendLine(FileName);
sb.Append("InternalName: ").AppendLine(InternalName);
sb.Append("OriginalFilename: ").AppendLine(OriginalFilename);
sb.Append("FileVersion: ").AppendLine(FileVersion);
sb.Append("FileDescription: ").AppendLine(FileDescription);
sb.Append("Product: ").AppendLine(ProductName);
sb.Append("ProductVersion: ").AppendLine(ProductVersion);
sb.Append("Debug: ").AppendLine(IsDebug.ToString());
sb.Append("Patched: ").AppendLine(IsPatched.ToString());
sb.Append("PreRelease: ").AppendLine(IsPreRelease.ToString());
sb.Append("PrivateBuild: ").AppendLine(IsPrivateBuild.ToString());
sb.Append("SpecialBuild: ").AppendLine(IsSpecialBuild.ToString());
sb.Append("Language: ").AppendLine(Language);
return sb.ToString();
}
}
}

View File

@@ -0,0 +1,33 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Reflection;
// Comments
[assembly:AssemblyDescriptionAttribute("Have you played a Contoso amusement device today?")]
// CompanyName
[assembly:AssemblyCompanyAttribute("The name of the company.")]
// FileDescription
[assembly:AssemblyTitleAttribute("My File")]
// FileVersion
[assembly:AssemblyFileVersionAttribute("4.3.2.1")]
// ProductVersion (overrides FileVersion to be the ProductVersion)
[assembly: AssemblyInformationalVersionAttribute("1.2.3-beta.4")]
// LegalCopyright
[assembly:AssemblyCopyrightAttribute("Copyright, you betcha!")]
// LegalTrademarks
[assembly:AssemblyTrademarkAttribute("TM")]
// Product
[assembly:AssemblyProductAttribute("The greatest product EVER")]
namespace System.Diagnostics.Tests
{
public class Test
{
public static void Main()
{
}
}
}

View File

@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition="'$(Configuration)'==''">Windows_Debug</Configuration>
</PropertyGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
<PropertyGroup>
<AssemblyName>System.Diagnostics.FileVersionInfo.TestAssembly</AssemblyName>
<ProjectGuid>{28EB14BE-3BC9-4543-ABA6-A932424DFBD0}</ProjectGuid>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
</PropertyGroup>
<!-- Default configurations to help VS understand the configurations -->
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Windows_Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Windows_Release|AnyCPU'" />
<!-- Compiled Source Files -->
<ItemGroup>
<Compile Include="Assembly1.cs" />
</ItemGroup>
<!-- Automatically added by VS -->
<ItemGroup>
<Service Include="{508349B6-6B84-4DF5-91F0-309BEEBAD82D}" />
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
</ItemGroup>
<ItemGroup>
<None Include="project.json" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
</Project>

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
<ItemGroup>
<Project Include="System.Diagnostics.FileVersionInfo.Tests\System.Diagnostics.FileVersionInfo.Tests.csproj">
<OSGroup>Unix</OSGroup>
</Project>
<Project Include="System.Diagnostics.FileVersionInfo.Tests\System.Diagnostics.FileVersionInfo.Tests.csproj">
<OSGroup>Windows_NT</OSGroup>
<TestTFMs>netcore50;netcoreapp1.0;net46</TestTFMs>
</Project>
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.traversal.targets))\dir.traversal.targets" />
</Project>

View File

@@ -0,0 +1,352 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using Xunit;
namespace System.Diagnostics.Tests
{
public class FileVersionInfoTest
{
private const string NativeConsoleAppFileName = "NativeConsoleApp.exe";
private const string NativeLibraryFileName = "NativeLibrary.dll";
private const string SecondNativeLibraryFileName = "SecondNativeLibrary.dll";
private const string TestAssemblyFileName = "System.Diagnostics.FileVersionInfo.TestAssembly.dll";
private const string TestCsFileName = "Assembly1.cs";
private const string TestNotFoundFileName = "notfound.dll";
[Fact]
[PlatformSpecific(TestPlatforms.Windows)] // native PE files only supported on Windows
public void FileVersionInfo_Normal()
{
// NativeConsoleApp (English)
VerifyVersionInfo(Path.Combine(Directory.GetCurrentDirectory(), NativeConsoleAppFileName), new MyFVI()
{
Comments = "",
CompanyName = "Microsoft Corporation",
FileBuildPart = 3,
FileDescription = "This is the description for the native console application.",
FileMajorPart = 5,
FileMinorPart = 4,
FileName = Path.Combine(Directory.GetCurrentDirectory(), NativeConsoleAppFileName),
FilePrivatePart = 2,
FileVersion = "5.4.3.2",
InternalName = NativeConsoleAppFileName,
IsDebug = false,
IsPatched = false,
IsPrivateBuild = false,
IsPreRelease = true,
IsSpecialBuild = true,
Language = GetFileVersionLanguage(0x0409), //English (United States)
LegalCopyright = "Copyright (C) 2050",
LegalTrademarks = "",
OriginalFilename = NativeConsoleAppFileName,
PrivateBuild = "",
ProductBuildPart = 3,
ProductMajorPart = 5,
ProductMinorPart = 4,
ProductName = Path.GetFileNameWithoutExtension(NativeConsoleAppFileName),
ProductPrivatePart = 2,
ProductVersion = "5.4.3.2",
SpecialBuild = ""
});
}
[Fact]
[PlatformSpecific(TestPlatforms.Windows)] // native PE files only supported on Windows
public void FileVersionInfo_Chinese()
{
// NativeLibrary.dll (Chinese)
VerifyVersionInfo(Path.Combine(Directory.GetCurrentDirectory(), NativeLibraryFileName), new MyFVI()
{
Comments = "",
CompanyName = "A non-existent company",
FileBuildPart = 3,
FileDescription = "Here is the description of the native library.",
FileMajorPart = 9,
FileMinorPart = 9,
FileName = Path.Combine(Directory.GetCurrentDirectory(), NativeLibraryFileName),
FilePrivatePart = 3,
FileVersion = "9.9.3.3",
InternalName = "NativeLi.dll",
IsDebug = false,
IsPatched = true,
IsPrivateBuild = false,
IsPreRelease = true,
IsSpecialBuild = false,
Language = GetFileVersionLanguage(0x0004),//Chinese (Simplified)
Language2 = GetFileVersionLanguage(0x0804),//Chinese (Simplified, PRC) - changed, but not yet on all platforms
LegalCopyright = "None",
LegalTrademarks = "",
OriginalFilename = "NativeLi.dll",
PrivateBuild = "",
ProductBuildPart = 40,
ProductMajorPart = 20,
ProductMinorPart = 30,
ProductName = "I was never given a name.",
ProductPrivatePart = 50,
ProductVersion = "20.30.40.50",
SpecialBuild = "",
});
}
[Fact]
[PlatformSpecific(TestPlatforms.Windows)] // native PE files only supported on Windows
public void FileVersionInfo_DifferentFileVersionAndProductVersion()
{
// Mtxex.dll
VerifyVersionInfo(Path.Combine(Directory.GetCurrentDirectory(), SecondNativeLibraryFileName), new MyFVI()
{
Comments = "",
CompanyName = "",
FileBuildPart = 0,
FileDescription = "",
FileMajorPart = 0,
FileMinorPart = 65535,
FileName = Path.Combine(Directory.GetCurrentDirectory(), SecondNativeLibraryFileName),
FilePrivatePart = 2,
FileVersion = "0.65535.0.2",
InternalName = "SecondNa.dll",
IsDebug = false,
IsPatched = false,
IsPrivateBuild = false,
IsPreRelease = false,
IsSpecialBuild = false,
Language = GetFileVersionLanguage(0x0400),//Process Default Language
LegalCopyright = "Copyright (C) 1 - 2014",
LegalTrademarks = "",
OriginalFilename = "SecondNa.dll",
PrivateBuild = "",
ProductBuildPart = 0,
ProductMajorPart = 1,
ProductMinorPart = 0,
ProductName = "Unknown_Product_Name",
ProductPrivatePart = 1,
ProductVersion = "1.0.0.1",
SpecialBuild = "",
});
}
[Fact]
public void FileVersionInfo_CustomManagedAssembly()
{
// Assembly1.dll
VerifyVersionInfo(Path.Combine(Directory.GetCurrentDirectory(), TestAssemblyFileName), new MyFVI()
{
Comments = "Have you played a Contoso amusement device today?",
CompanyName = "The name of the company.",
FileBuildPart = 2,
FileDescription = "My File",
FileMajorPart = 4,
FileMinorPart = 3,
FileName = Path.Combine(Directory.GetCurrentDirectory(), TestAssemblyFileName),
FilePrivatePart = 1,
FileVersion = "4.3.2.1",
InternalName = TestAssemblyFileName,
IsDebug = false,
IsPatched = false,
IsPrivateBuild = false,
IsPreRelease = false,
IsSpecialBuild = false,
Language = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? GetFileVersionLanguage(0x0000) : "Language Neutral",
LegalCopyright = "Copyright, you betcha!",
LegalTrademarks = "TM",
OriginalFilename = TestAssemblyFileName,
PrivateBuild = "",
ProductBuildPart = 3,
ProductMajorPart = 1,
ProductMinorPart = 2,
ProductName = "The greatest product EVER",
ProductPrivatePart = 0,
ProductVersion = "1.2.3-beta.4",
SpecialBuild = "",
});
}
[Fact]
public void FileVersionInfo_EmptyFVI()
{
// Assembly1.cs
VerifyVersionInfo(Path.Combine(Directory.GetCurrentDirectory(), TestCsFileName), new MyFVI()
{
Comments = null,
CompanyName = null,
FileBuildPart = 0,
FileDescription = null,
FileMajorPart = 0,
FileMinorPart = 0,
FileName = Path.Combine(Directory.GetCurrentDirectory(), TestCsFileName),
FilePrivatePart = 0,
FileVersion = null,
InternalName = null,
IsDebug = false,
IsPatched = false,
IsPrivateBuild = false,
IsPreRelease = false,
IsSpecialBuild = false,
Language = null,
LegalCopyright = null,
LegalTrademarks = null,
OriginalFilename = null,
PrivateBuild = null,
ProductBuildPart = 0,
ProductMajorPart = 0,
ProductMinorPart = 0,
ProductName = null,
ProductPrivatePart = 0,
ProductVersion = null,
SpecialBuild = null,
});
}
[Fact]
public void FileVersionInfo_FileNotFound()
{
Assert.Throws<FileNotFoundException>(() =>
FileVersionInfo.GetVersionInfo(Path.Combine(Directory.GetCurrentDirectory(), TestNotFoundFileName)));
}
// Additional Tests Wanted:
// [] File exists but we don't have permission to read it
// [] DLL has unknown codepage info
// [] DLL language/codepage is 8-hex-digits (locale > 0x999) (different codepath)
private void VerifyVersionInfo(String filePath, MyFVI expected)
{
FileVersionInfo fvi = FileVersionInfo.GetVersionInfo(filePath);
Assert.Equal(expected.Comments, fvi.Comments);
Assert.Equal(expected.CompanyName, fvi.CompanyName);
Assert.Equal(expected.FileBuildPart, fvi.FileBuildPart);
Assert.Equal(expected.FileDescription, fvi.FileDescription);
Assert.Equal(expected.FileMajorPart, fvi.FileMajorPart);
Assert.Equal(expected.FileMinorPart, fvi.FileMinorPart);
Assert.Equal(expected.FileName, fvi.FileName);
Assert.Equal(expected.FilePrivatePart, fvi.FilePrivatePart);
Assert.Equal(expected.FileVersion, fvi.FileVersion);
Assert.Equal(expected.InternalName, fvi.InternalName);
Assert.Equal(expected.IsDebug, fvi.IsDebug);
Assert.Equal(expected.IsPatched, fvi.IsPatched);
Assert.Equal(expected.IsPrivateBuild, fvi.IsPrivateBuild);
Assert.Equal(expected.IsPreRelease, fvi.IsPreRelease);
Assert.Equal(expected.IsSpecialBuild, fvi.IsSpecialBuild);
Assert.Contains(fvi.Language, new[] { expected.Language, expected.Language2 });
Assert.Equal(expected.LegalCopyright, fvi.LegalCopyright);
Assert.Equal(expected.LegalTrademarks, fvi.LegalTrademarks);
Assert.Equal(expected.OriginalFilename, fvi.OriginalFilename);
Assert.Equal(expected.PrivateBuild, fvi.PrivateBuild);
Assert.Equal(expected.ProductBuildPart, fvi.ProductBuildPart);
Assert.Equal(expected.ProductMajorPart, fvi.ProductMajorPart);
Assert.Equal(expected.ProductMinorPart, fvi.ProductMinorPart);
Assert.Equal(expected.ProductName, fvi.ProductName);
Assert.Equal(expected.ProductPrivatePart, fvi.ProductPrivatePart);
Assert.Equal(expected.ProductVersion, fvi.ProductVersion);
Assert.Equal(expected.SpecialBuild, fvi.SpecialBuild);
//ToString
String nl = Environment.NewLine;
Assert.Equal("File: " + fvi.FileName + nl +
"InternalName: " + fvi.InternalName + nl +
"OriginalFilename: " + fvi.OriginalFilename + nl +
"FileVersion: " + fvi.FileVersion + nl +
"FileDescription: " + fvi.FileDescription + nl +
"Product: " + fvi.ProductName + nl +
"ProductVersion: " + fvi.ProductVersion + nl +
"Debug: " + fvi.IsDebug.ToString() + nl +
"Patched: " + fvi.IsPatched.ToString() + nl +
"PreRelease: " + fvi.IsPreRelease.ToString() + nl +
"PrivateBuild: " + fvi.IsPrivateBuild.ToString() + nl +
"SpecialBuild: " + fvi.IsSpecialBuild.ToString() + nl +
"Language: " + fvi.Language + nl,
fvi.ToString());
}
internal class MyFVI
{
public string Comments;
public string CompanyName;
public int FileBuildPart;
public string FileDescription;
public int FileMajorPart;
public int FileMinorPart;
public string FileName;
public int FilePrivatePart;
public string FileVersion;
public string InternalName;
public bool IsDebug;
public bool IsPatched;
public bool IsPrivateBuild;
public bool IsPreRelease;
public bool IsSpecialBuild;
public string Language;
public string Language2;
public string LegalCopyright;
public string LegalTrademarks;
public string OriginalFilename;
public string PrivateBuild;
public int ProductBuildPart;
public int ProductMajorPart;
public int ProductMinorPart;
public string ProductName;
public int ProductPrivatePart;
public string ProductVersion;
public string SpecialBuild;
}
static string GetUnicodeString(String str)
{
if (str == null)
return "<null>";
StringBuilder buffer = new StringBuilder();
buffer.Append("\"");
for (int i = 0; i < str.Length; i++)
{
char ch = str[i];
if (ch == '\r')
{
buffer.Append("\\r");
}
else if (ch == '\n')
{
buffer.Append("\\n");
}
else if (ch == '\\')
{
buffer.Append("\\");
}
else if (ch == '\"')
{
buffer.Append("\\\"");
}
else if (ch == '\'')
{
buffer.Append("\\\'");
}
else if (ch < 0x20 || ch >= 0x7f)
{
buffer.Append("\\u");
buffer.Append(((int)ch).ToString("x4"));
}
else
{
buffer.Append(ch);
}
}
buffer.Append("\"");
return (buffer.ToString());
}
private static string GetFileVersionLanguage(uint langid)
{
var lang = new StringBuilder(256);
Interop.Kernel32.VerLanguageName(langid, lang, (uint)lang.Capacity);
return lang.ToString();
}
}
}

View File

@@ -0,0 +1,48 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition="'$(Configuration)'==''">Windows_Debug</Configuration>
</PropertyGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
<PropertyGroup>
<AssemblyName>System.Diagnostics.FileVersionInfo.Tests</AssemblyName>
<ProjectGuid>{6DFDB760-CC88-48AE-BD81-C64844EA3CBC}</ProjectGuid>
</PropertyGroup>
<!-- Default configurations to help VS understand the configurations -->
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
</PropertyGroup>
<ItemGroup>
<!-- Checked in test binaries for FileVersionInfoTest -->
<Content Include="NativeConsoleApp.exe">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="NativeLibrary.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="SecondNativeLibrary.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="..\System.Diagnostics.FileVersionInfo.TestAssembly\Assembly1.cs">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<Compile Include="FileVersionInfoTest.cs" />
<Compile Include="$(CommonPath)\Interop\Windows\Interop.Libraries.cs">
<Link>ProductionCode\Common\Interop\Windows\Interop.Libraries.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\Interop\Windows\kernel32\Interop.VerLanguageName.cs">
<Link>ProductionCode\Common\Interop\Windows\kernel32\Interop.VerLanguageName.cs</Link>
</Compile>
</ItemGroup>
<!-- References used -->
<ItemGroup>
<ProjectReference Include="..\System.Diagnostics.FileVersionInfo.TestAssembly\System.Diagnostics.FileVersionInfo.TestAssembly.csproj">
<Project>{28eb14be-3bc9-4543-aba6-a932424dfbd0}</Project>
<Name>System.Diagnostics.FileVersionInfo.TestAssembly</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
</Project>