You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET C#中FileVersionInfo.GetVersionInfo无法读取PyInstaller生成EXE属性

问题解决:读取PyInstaller生成EXE的版本信息(替代FileVersionInfo.GetVersionInfo)

问题背景

一直使用FileVersionInfo.GetVersionInfo读取可执行文件/DLL的版本属性,但遇到PyInstaller生成的EXE时,该方法无法读取信息,而文件资源管理器能正常查看。该EXE的版本信息定义示例如下:

VSVersionInfo(
  ffi=FixedFileInfo(
    filevers=(1, 2, 3, 4),
    prodvers=(1, 2, 3, 4),
    mask=0x3f,
    flags=0x0,
    OS=0x40004,
    fileType=0x1,
    subtype=0x0,
    date=(0, 0)
  ),
  kids=[
    StringFileInfo(
      [
      StringTable(
        u'040904B0',
        [StringStruct(u'CompanyName', u'Your Company Name'),
        StringStruct(u'FileDescription', u'Description of your program'),
        StringStruct(u'FileVersion', u'1.2.3.4'),
        StringStruct(u'InternalName', u'yourprogram'),
        StringStruct(u'LegalCopyright', u'© Your Company Name. All rights reserved.'),
        StringStruct(u'OriginalFilename', u'yourprogram.exe'),
        StringStruct(u'ProductName', u'Your Product Name'),
        StringStruct(u'ProductVersion', u'1.2.3.4')])
      ]), 
    VarFileInfo([VarStruct(u'Translation', [1033, 1200])])
  ]
)

目前通过调用version.dll的GetFileVersionInfo和VerQueryValue可以读取,但希望用更直观的实现方式。环境信息:

  • .NET Framework 4.8
  • Windows 10
  • 资源管理器可正常查看所有属性

原因分析

PyInstaller生成的EXE版本信息使用了UTF-16LE编码(对应Translation值1200),而FileVersionInfo.GetVersionInfo在处理这种编码的字符串表时存在兼容问题,导致无法正确解析信息。

解决方案:封装原生API为直观的.NET方法

把原生的版本信息读取API封装成静态类,提供简洁的调用接口,既避免繁琐的手动Marshal操作,又保持代码直观:

using System;
using System.Runtime.InteropServices;

public static class PyExeVersionReader
{
    [DllImport("version.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    private static extern bool GetFileVersionInfo(string lptstrFilename, IntPtr hHandle, uint dwLen, byte[] lpData);

    [DllImport("version.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    private static extern bool VerQueryValue(byte[] pBlock, string lpSubBlock, out IntPtr lplpBuffer, out uint puLen);

    [DllImport("version.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    private static extern uint GetFileVersionInfoSize(string lptstrFilename, out IntPtr lpdwHandle);

    public static string GetVersionProperty(string filePath, string propertyName)
    {
        uint bufferSize = GetFileVersionInfoSize(filePath, out _);
        if (bufferSize == 0)
            return null;

        byte[] buffer = new byte[bufferSize];
        if (!GetFileVersionInfo(filePath, IntPtr.Zero, bufferSize, buffer))
            return null;

        // 自动解析Translation获取字符串表路径
        if (VerQueryValue(buffer, @"\VarFileInfo\Translation", out IntPtr translationPtr, out uint translationLen))
        {
            ushort[] translation = new ushort[translationLen / 2];
            Marshal.Copy(translationPtr, translation, 0, translation.Length);
            string stringTablePath = $@"\StringFileInfo\{translation[0]:X4}{translation[1]:X4}\{propertyName}";
            
            if (VerQueryValue(buffer, stringTablePath, out IntPtr valuePtr, out uint valueLen))
            {
                return Marshal.PtrToStringUni(valuePtr);
            }
        }

        //  fallback到PyInstaller常用的040904B0编码表
        string fallbackPath = $@"\StringFileInfo\040904B0\{propertyName}";
        if (VerQueryValue(buffer, fallbackPath, out IntPtr fallbackPtr, out uint fallbackLen))
        {
            return Marshal.PtrToStringUni(fallbackPtr);
        }

        return null;
    }

    // 封装常用属性的快捷方法,调用方式接近FileVersionInfo
    public static string GetCompanyName(string filePath) => GetVersionProperty(filePath, "CompanyName");
    public static string GetFileDescription(string filePath) => GetVersionProperty(filePath, "FileDescription");
    public static string GetFileVersion(string filePath) => GetVersionProperty(filePath, "FileVersion");
    public static string GetProductName(string filePath) => GetVersionProperty(filePath, "ProductName");
}

使用示例

string exePath = @"C:\path\to\your\pyinstaller-built.exe";
string company = PyExeVersionReader.GetCompanyName(exePath);
string fileVersion = PyExeVersionReader.GetFileVersion(exePath);

Console.WriteLine($"厂商名称: {company}");
Console.WriteLine($"文件版本: {fileVersion}");

说明

  • 自动解析EXE的Translation信息,适配不同语言和编码的版本字符串表,无需硬编码路径
  • 提供的快捷方法调用风格和FileVersionInfo一致,保持代码直观性
  • 同时兼容PyInstaller生成的EXE和常规Windows可执行文件

内容的提问来源于stack exchange,提问作者vamshi krishna

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 22:21:07