Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/298.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在c#中使用VerQueryValue函数获取生成日期?_C#_C++ - Fatal编程技术网

如何在c#中使用VerQueryValue函数获取生成日期?

如何在c#中使用VerQueryValue函数获取生成日期?,c#,c++,C#,C++,我想在c#中使用VerQueryValue。但是我不知道我怎么用。 例如:本部分使用C++程序(exe或dll)编写生成日期,所以我必须得到这个生成日期< /p> VS_VERSION_INFO VERSIONINFO FILEVERSION BUILDVRS1,BUILDVRS2,BUILDVRS3,BUILDVRS4 PRODUCTVERSION BUILDVRS1,BUILDVRS2,BUILDVRS3,BUILDVRS0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG

我想在c#中使用VerQueryValue。但是我不知道我怎么用。 例如:本部分使用C++程序(exe或dll)编写生成日期,所以我必须得到这个生成日期< /p>
VS_VERSION_INFO VERSIONINFO
FILEVERSION BUILDVRS1,BUILDVRS2,BUILDVRS3,BUILDVRS4
PRODUCTVERSION BUILDVRS1,BUILDVRS2,BUILDVRS3,BUILDVRS0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
#else
FILEFLAGS 0x0L
#endif
FILEOS 0x4L
FILETYPE 0x2L
FILESUBTYPE 0x0L
BEGIN
    BLOCK "StringFileInfo"
    BEGIN
        BLOCK "040904b0"
        BEGIN
            VALUE "LastModified" , "20170313\0"
            VALUE "Comments", "\0"
            VALUE "CompanyName", BUILDCOMPANY
            VALUE "FileVersion", BUILDFILE
            VALUE "LegalCopyright", "Copyright (C) 1999-2002\0"
            VALUE "LegalTrademarks", "\0"
            VALUE "ProductVersion", BUILDPROD
            VALUE "InternalName", "SeriCom\0"
            VALUE "OriginalFilename", "SeriCom.DLL\0"
            VALUE "FileDescription", "SeriCom DLL\0"
            VALUE "ProductName", "SeriCom Dynamic Link Library\0"
            VALUE "BuildMach", BUILDMACH
            VALUE "BuildDate", BUILDDATE
            VALUE "BuildType", BUILDTYPE
            VALUE "BuildVers", BUILDVPRX
            VALUE "BuildNumb", BUILDNUMB
            VALUE "BuildChar", BUILDCHAR
            VALUE "BuildEnv1", BUILDCOMP
            VALUE "BuildEnv2", BUILDMFC
        END
    END
    BLOCK "VarFileInfo"
    BEGIN
        VALUE "Translation", 0x409, 1200
    END
END
我想在exe或dll文件中为获取构建日期编写c代码。

参考

用法示例:

var linkTimeLocal = Assembly.GetExecutingAssembly().GetLinkerTime();
参考

用法示例:

var linkTimeLocal = Assembly.GetExecutingAssembly().GetLinkerTime();

你可以用一些松饼

[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;
}
出于好奇,我开始探索的各种结构,并编写了一些代码:

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; }
    }
}
公共类版本信息
{
[DllImport(“version.dll”,CharSet=CharSet.Auto,SetLastError=true)]
publicstaticextern int getfileversioninfo大小(字符串lptstrFilename,out int lpdwHandle);
[DllImport(“version.dll”,CharSet=CharSet.Auto,SetLastError=true)]
公共静态外部bool GetFileVersionInfo(字符串lptstrFilename,int-dwHandle,int-dwLen,字节[]lpData);
[DllImport(“version.dll”,CharSet=CharSet.Auto,SetLastError=true)]
公共静态外部布尔值(字节[]pBlock,字符串lpSubBlock,out IntPtr lplpBuffer,out int puLen);
公共只读版本FileVersion;
公共只读版本ProductVersion;
公共只读uint文件标志掩码;
公共只读uint文件标志;
公共只读uint文件系统;
公共只读uint文件类型;
公共只读uint文件子类型;
//总是空的
公共只读日期时间?文件日期;
受保护的版本信息(版本文件版本、版本产品版本、uint文件标志任务、uint文件标志、uint文件操作系统、uint文件类型、uint文件子类型、日期时间?文件日期)
{
FileVersion=FileVersion;
ProductVersion=ProductVersion;
FileFlagsMask=FileFlagsMask;
FileFlags=FileFlags;
FileOS=FileOS;
FileType=FileType;
FileSubtype=FileSubtype;
FileDate=FileDate;
}
//vi在退出时可以为空
//Item1=语言|代码页
//第2项=关键
//第3项=价值
公共静态IEnumerable ReadVersionInfo(字符串文件名,out VersionInfo vi)
{
int-num;
int size=getFileVersionInfo大小(文件名,out num);
如果(大小==0)
{
抛出新的Win32Exception();
}
var buffer=新字节[大小];
bool success=GetFileVersionInfo(文件名、0、大小、缓冲区);
如果(!成功)
{
抛出新的Win32Exception();
}
返回ReadVersionInfo(缓冲区,输出vi);
}
//vi在退出时可以为空
//Item1=语言|代码页
//第2项=关键
//第3项=价值
公共静态IEnumerable ReadVersionInfo(字节[]缓冲区,out VersionInfo vi)
{
整数偏移量;
//此处计算的偏移量未使用
var fibs=ReadFileInfoBaseStruct(缓冲区,0,输出偏移量);
如果(fibs.Key!=“VS\u VERSION\u INFO”)
{
抛出新异常(fibs.Key);
}
//Value=VS_FIXEDFILEINFO
如果(fibs.ValueLength!=0)
{
uint signature=BitConverter.ToUInt32(缓冲区,fibs.ValueOffset);
如果(签名!=0xFEEF04BD)
{
抛出新异常(signature.ToString(“X8”);
}
uint strucVersion=位转换器.ToUInt32(缓冲区,fibs.ValueOffset+4);
var fileVersion=新版本(BitConverter.ToUInt16(缓冲区,fibs.ValueOffset+10)、BitConverter.ToUInt16(缓冲区,fibs.ValueOffset+8)、BitConverter.ToUInt16(缓冲区,fibs.ValueOffset+14)、BitConverter.ToUInt16(缓冲区,fibs.ValueOffset+12));
var productVersion=新版本(BitConverter.ToUInt16(缓冲区,fibs.ValueOffset+18)、BitConverter.ToUInt16(缓冲区,fibs.ValueOffset+16)、BitConverter.ToUInt16(缓冲区,fibs.ValueOffset+22)、BitConverter.ToUInt16(缓冲区,fibs.ValueOffset+20));
uint fileFlagsMask=BitConverter.ToUInt32(缓冲区,fibs.ValueOffset+24);
uint fileFlags=BitConverter.ToUInt32(缓冲区,fibs.ValueOffset+28);
uint fileOS=BitConverter.ToUInt32(缓冲区,fibs.ValueOffset+32);
uint fileType=BitConverter.ToUInt32(缓冲区,fibs.ValueOffset+36);
uint fileSubtype=BitConverter.ToUInt32(缓冲区,fibs.ValueOffset+40);
uint fileDateMS=BitConverter.ToUInt32(缓冲区,fibs.ValueOffset+44);
uint fileDateLS=BitConverter.ToUInt32(缓冲区,fibs.ValueOffset+48);
DateTime?fileDate=fileDateMS!=0 | | fileDateLS!=0?

(DateTime?)DateTime.FromFileTime((long)fileDateMS您可以使用一些pinvoke

[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;
}
出于好奇,我开始探索的各种结构,并编写了一些代码:

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; }
    }
}
公共类版本信息
{
[DllImport(“version.dll”,CharSet=CharSet.Auto,SetLastError=true)]
publicstaticextern int getfileversioninfo大小(字符串lptstrFilename,out int lpdwHandle);
[DllImport(“version.dll”,CharSet=CharSet.Auto,SetLastError=true)]
公共静态外部bool GetFileVersionInfo(字符串lptstrFilename,int-dwHandle,int-dwLen,字节[]lpData);
[DllImport(“version.dll”,CharSet=CharSet.Auto,SetLastError=true)]
公共静态外部布尔值(字节[]pBlock,字符串lpSubBlock,out IntPtr lplpBuffer,out int puLen);
公共只读版本FileVersion;
公共只读版本ProductVersion;
公共只读uint文件标志掩码;
公共只读uint文件标志;
公共只读uint文件系统;
公共只读uint文件类型;
公共只读uint文件子类型;
//总是空的
公共只读日期时间?文件日期;
受保护的版本信息(版本文件版本、版本产品版本、uint文件标志任务、uint文件标志、uint文件操作系统、uint文件类型、uint文件子类型、日期时间?文件日期)
{
FileVersion=FileVersion;
ProductVersion=ProductVersion;
FileFlagsMask=FileFlagsMask;
FileFlags=FileFlags;
FileOS=FileOS;
FileType=fileTy