我想在c#中使用VerQueryValue。但我不知道我该怎么用。 例如:这部分使用c ++程序(exe。或dll)编写了嵌入式构建日期。所以我必须得到这个构建日期
//##############
//# Javascript #
//##############
class NoteController{
constructor() {
this.store = new NoteStore(); // instance of a dataStore
}
HandleInputFields(){ // Enable / Disable a button by validation
var input = document.getElementById('edtNoteTitle').value; // Get the input text from the field
var inputIsValid = true;
if(input.length < 1) // text is empty
inputIsValid = false;
else if (this.store.notes.some(n => n.title === input)) // check for duplicates in the store
inputIsValid = false;
document.getElementById('btnCreateNote').disabled = !inputIsValid; // disable the button or keep it enabled
}
}
//########
//# HTML #
//########
<body onload="HandleInputFields()"> // Disable the button when loading the Document
<input type="text" id="edtNoteTitle" onchange="HandleInputFields()"> // Validate the Input field
</body>
我想在exe或dll文件中为get build date编写c#代码。
答案 0 :(得分:3)
你可以使用一些pinvokes ......
[DllImport("version.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern int GetFileVersionInfoSize(string lptstrFilename, out int lpdwHandle);
[DllImport("version.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool GetFileVersionInfo(string lptstrFilename, int dwHandle, int dwLen, byte[] lpData);
[DllImport("version.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool VerQueryValue(byte[] pBlock, string lpSubBlock, out IntPtr lplpBuffer, out int puLen);
public static Tuple<string, string>[] GetVersionInfo(string fileName, params string[] keys)
{
int num;
int size = GetFileVersionInfoSize(fileName, out num);
if (size == 0)
{
throw new Win32Exception();
}
var bytes = new byte[size];
bool success = GetFileVersionInfo(fileName, 0, size, bytes);
if (!success)
{
throw new Win32Exception();
}
int size2;
IntPtr ptr;
success = VerQueryValue(bytes, @"\VarFileInfo\Translation", out ptr, out size2);
uint[] langs;
if (success)
{
langs = new uint[size2 / 4];
for (int i = 0, j = 0; j < size2; i++, j += 4)
{
langs[i] = unchecked((uint)(((ushort)Marshal.ReadInt16(ptr, j) << 16) | (ushort)Marshal.ReadInt16(ptr, j + 2)));
}
}
else
{
// Taken from https://referencesource.microsoft.com/#System/services/monitoring/system/diagnosticts/FileVersionInfo.cs,470
langs = new uint[] { 0x040904B0, 0x040904E4, 0x04090000 };
}
string[] langs2 = Array.ConvertAll(langs, x => @"\StringFileInfo\" + x.ToString("X8") + @"\");
var kv = new Tuple<string, string>[keys.Length];
for (int i = 0; i < kv.Length; i++)
{
string key = keys[i];
string value = null;
foreach (var lang in langs2)
{
success = VerQueryValue(bytes, lang + key, out ptr, out size2);
if (success)
{
value = Marshal.PtrToStringUni(ptr);
break;
}
}
kv[i] = Tuple.Create(key, value);
}
return kv;
}
然后你使用:
string name = "Win32Project1.exe";
var infos = GetVersionInfo(name, "LastModified", "Comments", "CompanyName", "FileVersion", "LegalCopyright", "LegalTrademarks", "ProductVersion", "InternalName", "OriginalFilename", "FileDescription", "ProductName", "BuildDate");
var buildDate = infos.Single(x => x.Item1 == "BuildDate").Item2;
出于好奇,我开始探索VS_VERSIONINFO
的各种结构,并且我已经编写了一些代码:
public class VersionInfo
{
[DllImport("version.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern int GetFileVersionInfoSize(string lptstrFilename, out int lpdwHandle);
[DllImport("version.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool GetFileVersionInfo(string lptstrFilename, int dwHandle, int dwLen, byte[] lpData);
[DllImport("version.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool VerQueryValue(byte[] pBlock, string lpSubBlock, out IntPtr lplpBuffer, out int puLen);
public readonly Version FileVersion;
public readonly Version ProductVersion;
public readonly uint FileFlagsMask;
public readonly uint FileFlags;
public readonly uint FileOS;
public readonly uint FileType;
public readonly uint FileSubtype;
// Always null
public readonly DateTime? FileDate;
protected VersionInfo(Version fileVersion, Version productVersion, uint fileFlagsMask, uint fileFlags, uint fileOS, uint fileType, uint fileSubtype, DateTime? fileDate)
{
FileVersion = fileVersion;
ProductVersion = productVersion;
FileFlagsMask = fileFlagsMask;
FileFlags = fileFlags;
FileOS = fileOS;
FileType = fileType;
FileSubtype = fileSubtype;
FileDate = fileDate;
}
// vi can be null on exit
// Item1 = language | codepage
// Item2 = Key
// Item3 = Value
public static IEnumerable<Tuple<uint, string, string>> ReadVersionInfo(string fileName, out VersionInfo vi)
{
int num;
int size = GetFileVersionInfoSize(fileName, out num);
if (size == 0)
{
throw new Win32Exception();
}
var buffer = new byte[size];
bool success = GetFileVersionInfo(fileName, 0, size, buffer);
if (!success)
{
throw new Win32Exception();
}
return ReadVersionInfo(buffer, out vi);
}
// vi can be null on exit
// Item1 = language | codepage
// Item2 = Key
// Item3 = Value
public static IEnumerable<Tuple<uint, string, string>> ReadVersionInfo(byte[] buffer, out VersionInfo vi)
{
int offset;
// The offset calculated here is unused
var fibs = ReadFileInfoBaseStruct(buffer, 0, out offset);
if (fibs.Key != "VS_VERSION_INFO")
{
throw new Exception(fibs.Key);
}
// Value = VS_FIXEDFILEINFO
if (fibs.ValueLength != 0)
{
uint signature = BitConverter.ToUInt32(buffer, fibs.ValueOffset);
if (signature != 0xFEEF04BD)
{
throw new Exception(signature.ToString("X8"));
}
uint strucVersion = BitConverter.ToUInt32(buffer, fibs.ValueOffset + 4);
var fileVersion = new Version(BitConverter.ToUInt16(buffer, fibs.ValueOffset + 10), BitConverter.ToUInt16(buffer, fibs.ValueOffset + 8), BitConverter.ToUInt16(buffer, fibs.ValueOffset + 14), BitConverter.ToUInt16(buffer, fibs.ValueOffset + 12));
var productVersion = new Version(BitConverter.ToUInt16(buffer, fibs.ValueOffset + 18), BitConverter.ToUInt16(buffer, fibs.ValueOffset + 16), BitConverter.ToUInt16(buffer, fibs.ValueOffset + 22), BitConverter.ToUInt16(buffer, fibs.ValueOffset + 20));
uint fileFlagsMask = BitConverter.ToUInt32(buffer, fibs.ValueOffset + 24);
uint fileFlags = BitConverter.ToUInt32(buffer, fibs.ValueOffset + 28);
uint fileOS = BitConverter.ToUInt32(buffer, fibs.ValueOffset + 32);
uint fileType = BitConverter.ToUInt32(buffer, fibs.ValueOffset + 36);
uint fileSubtype = BitConverter.ToUInt32(buffer, fibs.ValueOffset + 40);
uint fileDateMS = BitConverter.ToUInt32(buffer, fibs.ValueOffset + 44);
uint fileDateLS = BitConverter.ToUInt32(buffer, fibs.ValueOffset + 48);
DateTime? fileDate = fileDateMS != 0 || fileDateLS != 0 ?
(DateTime?)DateTime.FromFileTime((long)fileDateMS << 32 | fileDateLS) :
null;
vi = new VersionInfo(fileVersion, productVersion, fileFlagsMask, fileFlags, fileOS, fileType, fileSubtype, fileDate);
}
else
{
vi = null;
}
return ReadVersionInfoInternal(buffer, fibs);
}
protected static IEnumerable<Tuple<uint, string, string>> ReadVersionInfoInternal(byte[] buffer, FileInfoBaseStruct fibs)
{
int sfiOrValOffset = (fibs.ValueOffset + fibs.ValueLength + 3) & (~3);
while (sfiOrValOffset < fibs.Length)
{
int nextSfiOrValOffset;
var sfiOrVal = ReadFileInfoBaseStruct(buffer, sfiOrValOffset, out nextSfiOrValOffset);
if (sfiOrVal.Key == "StringFileInfo")
{
int stOffset = sfiOrVal.ValueOffset;
while (stOffset < sfiOrVal.EndOffset)
{
int nextStOffset;
var st = ReadFileInfoBaseStruct(buffer, stOffset, out nextStOffset);
uint langCharset = uint.Parse(st.Key, NumberStyles.HexNumber);
int striOffset = st.ValueOffset;
while (striOffset < st.EndOffset)
{
int nextStriOffset;
var stri = ReadFileInfoBaseStruct(buffer, striOffset, out nextStriOffset);
// Here stri.ValueLength is in words!
int len = FindLengthUnicodeSZ(buffer, stri.ValueOffset, stri.ValueOffset + (stri.ValueLength * 2));
string value = Encoding.Unicode.GetString(buffer, stri.ValueOffset, len * 2);
yield return Tuple.Create(langCharset, stri.Key, value);
striOffset = nextStriOffset;
}
stOffset = nextStOffset;
}
}
else if (sfiOrVal.Key == "VarFileInfo")
{
int varOffset = sfiOrVal.ValueOffset;
while (varOffset < sfiOrVal.EndOffset)
{
int nextVarOffset;
var var = ReadFileInfoBaseStruct(buffer, varOffset, out nextVarOffset);
if (var.Key != "Translation")
{
throw new Exception(var.Key);
}
int langOffset = var.ValueOffset;
while (langOffset < var.EndOffset)
{
unchecked
{
// We invert the order suggested by the Var description!
uint high = (uint)BitConverter.ToInt16(buffer, langOffset);
uint low = (uint)BitConverter.ToInt16(buffer, langOffset + 2);
uint lang = (high << 16) | low;
langOffset += 4;
}
}
varOffset = nextVarOffset;
}
}
else
{
Debug.WriteLine("Unrecognized " + sfiOrVal.Key);
}
sfiOrValOffset = nextSfiOrValOffset;
}
}
protected static FileInfoBaseStruct ReadFileInfoBaseStruct(byte[] buffer, int offset, out int nextOffset)
{
var fibs = new FileInfoBaseStruct
{
Length = BitConverter.ToInt16(buffer, offset),
ValueLength = BitConverter.ToInt16(buffer, offset + 2),
Type = BitConverter.ToInt16(buffer, offset + 4)
};
int len = FindLengthUnicodeSZ(buffer, offset + 6, offset + fibs.Length);
fibs.Key = Encoding.Unicode.GetString(buffer, offset + 6, len * 2);
// Padding
fibs.ValueOffset = ((offset + 6 + (len + 1) * 2) + 3) & (~3);
fibs.EndOffset = offset + fibs.Length;
nextOffset = (fibs.EndOffset + 3) & (~3);
return fibs;
}
protected static int FindLengthUnicodeSZ(byte[] buffer, int offset, int endOffset)
{
int offset2 = offset;
while (offset2 < endOffset && BitConverter.ToInt16(buffer, offset2) != 0)
{
offset2 += 2;
}
// In chars
return (offset2 - offset) / 2;
}
// Used internally
protected class FileInfoBaseStruct
{
public short Length { get; set; }
public short ValueLength { get; set; }
public short Type { get; set; }
public string Key { get; set; }
public int ValueOffset { get; set; }
public int EndOffset { get; set; }
}
}
使用它像:
string name = "Win32Project1-loc.exe";
// vi could be null on return from ReadVersionInfo
VersionInfo vi;
// Note that it is an IEnumerable<>... If you want to use
// it multipel times, you should .ToArray() it!
var infos = VersionInfo.ReadVersionInfo(name, out vi);
// For example
var buildDate = infos.Single(x => x.Item2 == "BuildDate").Item3;
答案 1 :(得分:0)
public static DateTime GetLinkerTime(this Assembly assembly, TimeZoneInfo target = null)
{
var filePath = assembly.Location;
const int c_PeHeaderOffset = 60;
const int c_LinkerTimestampOffset = 8;
var buffer = new byte[2048];
using (var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read))
stream.Read(buffer, 0, 2048);
var offset = BitConverter.ToInt32(buffer, c_PeHeaderOffset);
var secondsSince1970 = BitConverter.ToInt32(buffer, offset + c_LinkerTimestampOffset);
var epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
var linkTimeUtc = epoch.AddSeconds(secondsSince1970);
var tz = target ?? TimeZoneInfo.Local;
var localTime = TimeZoneInfo.ConvertTimeFromUtc(linkTimeUtc, tz);
return localTime;
}
用法示例:
var linkTimeLocal = Assembly.GetExecutingAssembly().GetLinkerTime();