1
0
Fork 0
mirror of https://github.com/beefytech/Beef.git synced 2025-06-10 20:42:21 +02:00

Added file version

This commit is contained in:
Brian Fiete 2019-09-18 08:13:00 -07:00
parent f2863d53b8
commit 28c24e98d7
2 changed files with 651 additions and 49 deletions

View file

@ -0,0 +1,593 @@
// This file contains portions of code released by Microsoft under the MIT license as part
// of an open-sourcing initiative in 2014 of the C# core libraries.
// The original source was submitted to https://github.com/Microsoft/referencesource
namespace System.Diagnostics
{
using System.Text;
using System.IO;
using System.Security;
using System;
using System.Globalization;
public class FileVersionInfo
{
public enum Error
{
FileNotFound,
NotSupported
}
private String mFileName ~ delete _;
private String mCompanyName ~ delete _;
private String mFileDescription ~ delete _;
private String mFileVersion ~ delete _;
private String mInternalName ~ delete _;
private String mLegalCopyright ~ delete _;
private String mOriginalFilename ~ delete _;
private String mProductName ~ delete _;
private String mProductVersion ~ delete _;
private String mComments ~ delete _;
private String mLegalTrademarks ~ delete _;
private String mPrivateBuild ~ delete _;
private String mSpecialBuild ~ delete _;
private String mLanguage ~ delete _;
private int32 mFileMajor;
private int32 mFileMinor;
private int32 mFileBuild;
private int32 mFilePrivate;
private int32 mProductMajor;
private int32 mProductMinor;
private int32 mProductBuild;
private int32 mProductPrivate;
private int32 mFileFlags;
public void Dispose()
{
DeleteAndNullify!(mFileName);
DeleteAndNullify!(mCompanyName);
DeleteAndNullify!(mFileDescription);
DeleteAndNullify!(mFileVersion);
DeleteAndNullify!(mInternalName);
DeleteAndNullify!(mLegalCopyright);
DeleteAndNullify!(mOriginalFilename);
DeleteAndNullify!(mProductName);
DeleteAndNullify!(mProductVersion);
DeleteAndNullify!(mComments);
DeleteAndNullify!(mLegalTrademarks);
DeleteAndNullify!(mPrivateBuild);
DeleteAndNullify!(mSpecialBuild);
DeleteAndNullify!(mLanguage);
mFileMajor = 0;
mFileMajor = 0;
mFileBuild = 0;
mFilePrivate = 0;
mProductMajor = 0;
mProductMinor = 0;
mProductBuild = 0;
mProductPrivate = 0;
mFileFlags = 0;
}
/// Gets the comments associated with the file.
public StringView Comments
{
get
{
return mComments;
}
}
/// >Gets the name of the company that produced the file.
public StringView CompanyName
{
get
{
return mCompanyName;
}
}
/// Gets the build number of the file.
public int FileBuildPart
{
get
{
return mFileBuild;
}
}
/// Gets the description of the file.
///
public String FileDescription
{
get
{
return mFileDescription;
}
}
///
/// Gets the major part of the version number.
///
public int FileMajorPart
{
get
{
return mFileMajor;
}
}
///
/// Gets the minor
/// part of the version number of the file.
///
public int FileMinorPart
{
get
{
return mFileMinor;
}
}
///
/// Gets the name of the file that this instance describes.
///
public String FileName
{
get
{
return mFileName;
}
}
///
/// Gets the file private part number.
///
public int FilePrivatePart
{
get
{
return mFilePrivate;
}
}
///
/// Gets the file version number.
///
public String FileVersion
{
get
{
return mFileVersion;
}
}
///
/// Gets the internal name of the file, if one exists.
///
public String InternalName
{
get
{
return mInternalName;
}
}
///
/// Gets a value that specifies whether the file
/// contains debugging information or is compiled with debugging features enabled.
///
public bool IsDebug
{
get
{
#if BF_PLATFORM_WINDOWS
return (mFileFlags & Windows.VS_FF_DEBUG) != 0;
#else
return false;
#endif
}
}
///
/// 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.
///
public bool IsPatched
{
get
{
#if BF_PLATFORM_WINDOWS
return (mFileFlags & Windows.VS_FF_PATCHED) != 0;
#else
return false;
#endif
}
}
///
/// Gets a value that specifies whether the file was built using standard release procedures.
///
public bool IsPrivateBuild
{
get
{
#if BF_PLATFORM_WINDOWS
return (mFileFlags & Windows.VS_FF_PRIVATEBUILD) != 0;
#else
return false;
#endif
}
}
///
/// Gets a value that specifies whether the file
/// is a development version, rather than a commercially released product.
///
public bool IsPreRelease
{
get
{
#if BF_PLATFORM_WINDOWS
return (mFileFlags & Windows.VS_FF_PRERELEASE) != 0;
#else
return false;
#endif
}
}
///
/// Gets a value that specifies whether the file is a special build.
///
public bool IsSpecialBuild
{
get
{
#if BF_PLATFORM_WINDOWS
return (mFileFlags & Windows.VS_FF_SPECIALBUILD) != 0;
#else
return false;
#endif
}
}
///
///
/// Gets the default language String for the version info block.
///
///
public String Language
{
get
{
return mLanguage;
}
}
///
/// Gets all copyright notices that apply to the specified file.
///
public String LegalCopyright
{
get
{
return mLegalCopyright;
}
}
///
/// Gets the trademarks and registered trademarks that apply to the file.
///
public String LegalTrademarks
{
get
{
return mLegalTrademarks;
}
}
///
/// Gets the name the file was created with.
///
public String OriginalFilename
{
get
{
return mOriginalFilename;
}
}
///
/// Gets information about a private version of the file.
///
public String PrivateBuild
{
get
{
return mPrivateBuild;
}
}
///
/// Gets the build number of the product this file is associated with.
///
public int ProductBuildPart
{
get
{
return mProductBuild;
}
}
///
/// Gets the major part of the version number for the product this file is associated with.
///
public int ProductMajorPart
{
get
{
return mProductMajor;
}
}
///
/// Gets the minor part of the version number for the product the file is associated with.
///
public int ProductMinorPart
{
get
{
return mProductMinor;
}
}
///
/// Gets the name of the product this file is distributed with.
///
public String ProductName
{
get
{
return mProductName;
}
}
///
/// Gets the private part number of the product this file is associated with.
///
public int ProductPrivatePart
{
get
{
return mProductPrivate;
}
}
///
/// Gets the version of the product this file is distributed with.
///
public String ProductVersion
{
get
{
return mProductVersion;
}
}
///
/// Gets the special build information for the file.
///
public String SpecialBuild
{
get
{
return mSpecialBuild;
}
}
private static void ConvertTo8DigitHex(int value, String s)
{
s.AppendF("{:X8}", value);
}
#if BF_PLATFORM_WINDOWS
private static Windows.VS_FIXEDFILEINFO GetFixedFileInfo(void* memPtr)
{
void* memRef = null;
if (Windows.VerQueryValueW(memPtr, "\\".ToScopedNativeWChar!(), ref memRef, var memLen))
return *(Windows.VS_FIXEDFILEINFO*)memRef;
return .();
}
private static String GetFileVersionLanguage(void* memPtr)
{
int langid = GetVarEntry(memPtr) >> 16;
char16[256] langChars = .(0, ?);
Windows.VerLanguageNameW((uint32)langid, &langChars, (uint32)langChars.Count);
return new String()..Append(&langChars);
}
private static String GetFileVersionString(void* memPtr, String name)
{
String str = new String();
void* memRef = null;
if (Windows.VerQueryValueW(memPtr, name.ToScopedNativeWChar!(), ref memRef, var memLen))
{
if (memRef != null)
{
str.Append((char16*)memRef);
}
}
return str;
}
private static int32 GetVarEntry(void* memPtr)
{
void* memRef = null;
if (Windows.VerQueryValueW(memPtr, "\\VarFileInfo\\Translation".ToScopedNativeWChar!(), ref memRef, var memLen))
{
return ((int32)(*(int16*)(memRef)) << 16) + *(int16*)((uint8*)memRef + 2);
}
return 0x040904E4;
}
//
// This function tries to find version informaiton for a specific codepage.
// Returns true when version information is found.
//
private bool GetVersionInfoForCodePage(void* memIntPtr, String codepage)
{
StringView template = "\\\\StringFileInfo\\\\{0}\\\\{1}";
mCompanyName = GetFileVersionString(memIntPtr, scope String()..AppendF(CultureInfo.InvariantCulture, template, codepage, "CompanyName"));
mFileDescription = GetFileVersionString(memIntPtr, scope String()..AppendF(CultureInfo.InvariantCulture, template, codepage, "FileDescription"));
mFileVersion = GetFileVersionString(memIntPtr, scope String()..AppendF(CultureInfo.InvariantCulture, template, codepage, "FileVersion"));
mInternalName = GetFileVersionString(memIntPtr, scope String()..AppendF(CultureInfo.InvariantCulture, template, codepage, "InternalName"));
mLegalCopyright = GetFileVersionString(memIntPtr, scope String()..AppendF(CultureInfo.InvariantCulture, template, codepage, "LegalCopyright"));
mOriginalFilename = GetFileVersionString(memIntPtr, scope String()..AppendF(CultureInfo.InvariantCulture, template, codepage, "OriginalFilename"));
mProductName = GetFileVersionString(memIntPtr, scope String()..AppendF(CultureInfo.InvariantCulture, template, codepage, "ProductName"));
mProductVersion = GetFileVersionString(memIntPtr, scope String()..AppendF(CultureInfo.InvariantCulture, template, codepage, "ProductVersion"));
mComments = GetFileVersionString(memIntPtr, scope String()..AppendF(CultureInfo.InvariantCulture, template, codepage, "Comments"));
mLegalTrademarks = GetFileVersionString(memIntPtr, scope String()..AppendF(CultureInfo.InvariantCulture, template, codepage, "LegalTrademarks"));
mPrivateBuild = GetFileVersionString(memIntPtr, scope String()..AppendF(CultureInfo.InvariantCulture, template, codepage, "PrivateBuild"));
mSpecialBuild = GetFileVersionString(memIntPtr, scope String()..AppendF(CultureInfo.InvariantCulture, template, codepage, "SpecialBuild"));
mLanguage = GetFileVersionLanguage(memIntPtr);
Windows.VS_FIXEDFILEINFO ffi = GetFixedFileInfo(memIntPtr);
mFileMajor = HIWORD(ffi.dwFileVersionMS);
mFileMinor = LOWORD(ffi.dwFileVersionMS);
mFileBuild = HIWORD(ffi.dwFileVersionLS);
mFilePrivate = LOWORD(ffi.dwFileVersionLS);
mProductMajor = HIWORD(ffi.dwProductVersionMS);
mProductMinor = LOWORD(ffi.dwProductVersionMS);
mProductBuild = HIWORD(ffi.dwProductVersionLS);
mProductPrivate = LOWORD(ffi.dwProductVersionLS);
mFileFlags = (.)ffi.dwFileFlags;
// fileVersion is chosen based on best guess. Other fields can be used if appropriate.
return (mFileVersion != string.Empty);
}
///
/// <para>Returns a System.Windows.Forms.FileVersionInfo representing the version information associated with the specified file.
///
public Result<void, Error> GetVersionInfo(StringView fileName)
{
if (mFileName != null)
{
Dispose();
}
// Check for the existence of the file. File.Exists returns false
// if Read permission is denied.
if (!File.Exists(fileName))
{
//
// The previous version of this code in the success case would require
// one imperative Assert for PathDiscovery permission, one Demand for
// PathDiscovery permission (blocked by the Assert), and 2 demands for
// Read permission. It turns out that File.Exists does a demand for
// Read permission, so in the success case, we only need to do a single Demand.
// In the success case, this change increases the performance of this
// function dramatically.
//
// In the failure case, we want to remain backwardly compatible by throwing
// a SecurityException in the case where Read access is denied
// (it can be argued that this is less secure than throwing a FileNotFoundException,
// but perhaps not so much as to be worth a breaking change).
// File.Exists eats a SecurityException, so we need to Demand for it
// here. Since performance in the failure case is not crucial, as an
// exception will be thrown anyway, we do a Demand for Read access.
// If that does not throw an exception, then we will throw a FileNotFoundException.
//
// We also change the code to do a declarative Assert for PathDiscovery,
// as that performs much better than an imperative Assert.
//
return .Err(.FileNotFound);
}
mFileName = new String(fileName);
char16* wcStr = fileName.ToScopedNativeWChar!();
uint32 handle; // This variable is not used, but we need an out variable.
uint32 infoSize = Windows.GetFileVersionInfoSizeW(wcStr, out handle);
if (infoSize != 0)
{
uint8* memPtr = new:ScopedAlloc! uint8[infoSize]*;
if (Windows.GetFileVersionInfoW(wcStr, 0, infoSize, memPtr))
{
int langid = GetVarEntry(memPtr);
String langStr = scope .();
ConvertTo8DigitHex(langid, langStr);
if (!GetVersionInfoForCodePage(memPtr, langStr))
{
// Some dlls might not contain correct codepage information. In this case we will fail during lookup.
// Explorer will take a few shots in dark by trying following ID:
//
// 040904B0 // US English + CP_UNICODE
// 040904E4 // US English + CP_USASCII
// 04090000 // US English + unknown codepage
// Explorer also randomly guess 041D04B0=Swedish+CP_UNICODE and 040704B0=German+CP_UNICODE) sometimes.
// We will try to simulate similiar behavior here.
int[] ids = scope .(0x040904B0, 0x040904E4, 0x04090000);
for (int id in ids)
{
if (id != langid)
{
String idStr = scope .();
ConvertTo8DigitHex(id, idStr);
if (GetVersionInfoForCodePage(memPtr, idStr))
{
break;
}
}
}
}
}
}
return .Ok;
}
#else
public Result<void, Error> GetVersionInfo(StringView fileName)
{
return .Err(.NotSupported);
}
#endif
private static int32 HIWORD(uint32 val)
{
return (.)((val << 16) & 0xFFFF);
}
private static int32 LOWORD(uint32 val)
{
return (.)(val & 0xFFFF);
}
///
/// <para>Returns a partial list of properties in System.Windows.Forms.FileVersionInfo
/// and their values.
///
public override void ToString(String str)
{
String nl = "\r\n";
str.Append("File: "); str.Append(FileName); str.Append(nl);
str.Append("InternalName: "); str.Append(InternalName); str.Append(nl);
str.Append("OriginalFilename: "); str.Append(OriginalFilename); str.Append(nl);
str.Append("FileVersion: "); str.Append(FileVersion); str.Append(nl);
str.Append("FileDescription: "); str.Append(FileDescription); str.Append(nl);
str.Append("Product: "); str.Append(ProductName); str.Append(nl);
str.Append("ProductVersion: "); str.Append(ProductVersion); str.Append(nl);
str.Append("Debug: "); IsDebug.ToString(str); str.Append(nl);
str.Append("Patched: "); IsPatched.ToString(str); str.Append(nl);
str.Append("PreRelease: "); IsPreRelease.ToString(str); str.Append(nl);
str.Append("PrivateBuild: "); IsPrivateBuild.ToString(str); str.Append(nl);
str.Append("SpecialBuild: "); IsSpecialBuild.ToString(str); str.Append(nl);
str.Append("Language: "); str.Append(Language); str.Append(nl);
}
}
}