C#PInvoke VerQueryValue返回OutOfMemoryException?

问题描述 投票:2回答:2

下面是我从在线资源获得的代码示例,但它假设使用fullframework,但是当我尝试使用C#智能设备构建它时,它会抛出异常,说它是内存不足。有谁知道如何修复它在紧凑型上使用?当我第二次调用最后一个VerQueryValue时出现内存不足异常。

谢谢,

    [DllImport("coredll.dll")]
    public static extern bool VerQueryValue(byte[] buffer, string subblock, out IntPtr blockbuffer, out uint len);

    [DllImport("coredll.dll")]
    public static extern bool VerQueryValue(byte[] pBlock, string pSubBlock, out string pValue, out uint len);    
    //
    private static void GetAssemblyVersion()
    {

        string filename = @"\Windows\MyLibrary.dll";
        if (File.Exists(filename))
        {
            try                {

                int handle = 0;
                Int32 size = 0;
                size = GetFileVersionInfoSize(filename, out handle);

                if (size > 0)
                {
                    bool retValue;
                    byte[] buffer = new byte[size];
                    retValue = GetFileVersionInfo(filename, handle, size, buffer);
                    if (retValue == true)
                    {
                        bool success = false;
                        IntPtr blockbuffer = IntPtr.Zero;
                        uint len = 0;
                        //success = VerQueryValue(buffer, "\\", out blockbuffer, out len);
                        success = VerQueryValue(buffer, @"\VarFileInfo\Translation", out blockbuffer, out len);

                        if(success)
                        {
                            int p = (int)blockbuffer;

                            //Reads a 16-bit signed integer from unmanaged memory
                            int j = Marshal.ReadInt16((IntPtr)p);
                            p += 2;

                            //Reads a 16-bit signed integer from unmanaged memory
                            int k = Marshal.ReadInt16((IntPtr)p);

                            string sb = string.Format("{0:X4}{1:X4}", j, k);
                            string spv = @"\StringFileInfo\" + sb + @"\ProductVersion";

                            string versionInfo;
                            VerQueryValue(buffer, spv, out versionInfo, out len);
                        }    
                    }
                }
            }
            catch (Exception err)
            {
                string error = err.Message;
            }
        }
    }
c# compact-framework
2个回答
0
投票

添加这两个语句后:

                            Int32 dwVerMinor = j & 0xffff;
                            Int32 dwVerBuild = k & 0xffff;

它能够检索DLL版本。


0
投票

这是一个实现:

using DWORD = System.UInt32;

public static class NativeFile
{
    public struct NativeFileInfo
    {
        public Version Version;
        public NameValueCollection StringTable;
    }

    public unsafe static NativeFileInfo GetFileInfo(string path)
    {
        if (!File.Exists(path))
        {
            throw new FileNotFoundException();
        }

        IntPtr handle;

        var size = GetFileVersionInfoSize(path, out handle);
        var buffer = Marshal.AllocHGlobal(size);

        try
        {
            if (!GetFileVersionInfo(path, handle, size, buffer))
            {
                throw new Win32Exception(Marshal.GetLastWin32Error());
            }

            IntPtr pVersion;
            int versionLength;

            VerQueryValue(buffer, “\”, out pVersion, out versionLength);

            var versionInfo = (VS_FIXEDFILEINFO)Marshal.PtrToStructure(pVersion, typeof(VS_FIXEDFILEINFO));

            var version = new Version((int)versionInfo.dwFileVersionMS >> 16,
                                      (int)versionInfo.dwFileVersionMS & 0xFFFF,
                                      (int)versionInfo.dwFileVersionLS >> 16,
                                      (int)versionInfo.dwFileVersionLS & 0xFFFF);

            // move to the string table and parse
            var pStringTable = ((byte*)pVersion.ToPointer()) + versionLength;
            var strings = ParseStringTable(pStringTable, size – versionLength);

            return new NativeFileInfo
            {
                Version = version,
                StringTable = strings
            };
        }
        finally
        {
            Marshal.FreeHGlobal(buffer);
        }
    }

    private unsafe static NameValueCollection ParseStringTable(byte* pStringTable, int length)
    {
        NameValueCollection nvc = new NameValueCollection();

        byte* p = pStringTable;
        short stringFileInfoLength = (short)*p;
        byte* end = pStringTable + length;

        p += (2 + 2 + 2); // length + valuelength + type

        // verify key
        var key = Marshal.PtrToStringUni(new IntPtr(p), 14);
        if (key != "StringFileInfo") throw new ArgumentException();

        // move past the key to the first string table
        p += 30;
        short stringTableLength = (short)*p;
        p += (2 + 2 + 2); // length + valuelength + type

        // get locale info
        key = Marshal.PtrToStringUni(new IntPtr(p), 8);

        // move to the first string
        p += 18;

        while (p < end)
        {
            short stringLength = (short)*p;
            p += 2;
            short valueChars = (short)*p;
            p += 2;
            short type = (short)*p;
            p += 2;

            if (stringLength == 0) break;

            if ((valueChars == 0) || (type != 1))
            {
                p += stringLength;
                continue;
            }

            var keyLength = stringLength – (valueChars * 2) – 6;
            key = Marshal.PtrToStringUni(new IntPtr(p), keyLength / 2).TrimEnd(”);
            p += keyLength;

            var value = Marshal.PtrToStringUni(new IntPtr(p), valueChars).TrimEnd(”);
            p += valueChars * 2;

            if ((int)p % 4 != 0) p += 2;

            nvc.Add(key, value);
        }

        return nvc;
    }


    private const string COREDLL = "coredll.dll";

    [DllImport(COREDLL, SetLastError = true)]
    private static extern int GetFileVersionInfoSize(string lptstrFilename, out IntPtr lpdwHandle);

    [DllImport(COREDLL, SetLastError = true)]
    private static extern bool GetFileVersionInfo(string lptstrFilename, IntPtr dwHandle, int dwLen, IntPtr lpData);

    [DllImport(COREDLL, SetLastError = true)]
    private static extern bool VerQueryValue(IntPtr pBlock, string lpSubBlock, out IntPtr lplpBuffer, out int puLen);

    [StructLayout(LayoutKind.Sequential)]
    private struct VS_FIXEDFILEINFO
    {
        public DWORD dwSignature;
        public DWORD dwStrucVersion;
        public DWORD dwFileVersionMS;
        public DWORD dwFileVersionLS;
        public DWORD dwProductVersionMS;
        public DWORD dwProductVersionLS;
        public DWORD dwFileFlagsMask;
        public DWORD dwFileFlags;
        public FileOS dwFileOS;
        public FileType dwFileType;
        public DWORD dwFileSubtype;
        public DWORD dwFileDateMS;
        public DWORD dwFileDateLS;
    };

    public enum FileOS : uint
    {
        Unknown = 0x00000000,
        DOS = 0x00010000,
        OS2_16 = 0x00020000,
        OS2_32 = 0x00030000,
        NT = 0x00040000,
        WindowsCE = 0x00050000,
    }

    public enum FileType : uint
    {
        Unknown = 0x00,
        Application = 0x01,
        DLL = 0x02,
        Driver = 0x03,
        Font = 0x04,
        VXD = 0x05,
        StaticLib = 0x07
    }
}

以及用法示例:

class Program
{

    static void Main(string[] args)
    {
        string target = “\FlashFX Disk\ARMv4i\conmanclient2.exe”;
        var version = NativeFile.GetFileInfo(target);

        Console.WriteLine(string.Format(“File: { 0}”, Path.GetFileName(target)));
        Console.WriteLine(string.Format(“Version: { 0}”, version.Version.ToString(4)));

        foreach (var key in version.StringTable.AllKeys)
        {
            Console.WriteLine(string.Format(“{ 0}: { 1}”, key, version.StringTable[key]));
        }

        Console.ReadLine();
    }
© www.soinside.com 2019 - 2024. All rights reserved.