17370845950

Python中使用win32api获取Windows可执行文件版本号的正确方法

本文介绍如何在python中可靠获取.exe文件的版本号,解决使用win32com的scripting.filesystemobject调用getfileversion时频繁报错(pywintypes.com_error)的问题,并提供基于win32api的稳定替代方案。

Scripting.FileSystemObject.

GetFileVersion 在现代Windows系统(尤其是64位环境或UAC启用时)中存在严重兼容性问题:它依赖于已过时的COM组件,对非系统签名文件、无版本资源的PE文件或受保护路径下的文件常返回-2147024894(即ERROR_FILE_NOT_FOUND的HRESULT等效值),即使文件真实存在且可读。该错误与路径编码、权限或文件类型无关,本质是COM接口本身对新版PE结构和UAC沙箱的支持缺失。

推荐改用 win32api.GetFileVersionInfo —— 它直接调用Windows原生API GetFileVersionInfo(),绕过COM层,稳定性高、兼容性强,且能正确解析嵌入在PE文件资源段中的版本信息(VS_VERSIONINFO)。

以下是完整、健壮的实现示例:

from win32api import GetFileVersionInfo, LOWORD, HIWORD

def get_version_number(filename):
    """
    获取Windows可执行文件(.exe/.dll等)的文件版本号,格式为 a.b.c.d
    返回元组 (major, minor, build, revision),失败时返回 (0, 0, 0, 0)
    """
    try:
        # 获取版本信息块(根块"\\"表示主版本资源)
        info = GetFileVersionInfo(filename, "\\")
        # 解析FileVersion字段(MS: Most Significant, LS: Least Significant)
        ms = info['FileVersionMS']
        ls = info['FileVersionLS']
        return (
            HIWORD(ms),   # 主版本号(高位字)
            LOWORD(ms),   # 次版本号(低位字)
            HIWORD(ls),   # 构建号(高位字)
            LOWORD(ls)    # 修订号(低位字)
        )
    except Exception as e:
        print(f"获取版本信息失败: {e}")
        return 0, 0, 0, 0

# 使用示例
file_path = r'C:\Users\Alex\Downloads\ChromeSetup.exe'
version_tuple = get_version_number(file_path)
version_str = ".".join(map(str, version_tuple))  # 更简洁的拼接方式
print(f"文件版本: {version_str}")  # 输出如:125.0.6422.142

关键说明与注意事项:

  • ✅ 必须安装 pywin32(pip install pywin32),无需额外注册COM组件;
  • ✅ 支持 .exe、.dll、.sys 等含版本资源的PE文件;若文件无版本信息(如某些便携版工具),将返回 (0,0,0,0);
  • ⚠️ 路径必须为绝对路径,且确保Python进程有读取权限(避免UAC虚拟化路径干扰,建议避开C:\Program Files\等受保护目录进行测试);
  • ⚠️ GetFileVersionInfo 不支持网络路径(UNC)或重定向符号链接,需传入本地物理路径;
  • ? 如需获取产品版本(ProductVersion)、公司名(CompanyName)等其他属性,可进一步解析 info['StringFileInfo'] 字典(需配合win32api的VerQueryValue扩展使用)。

该方法已在Windows 10/11 + Python 3.8–3.12 + pywin32 306+ 环境中验证通过,是生产环境中获取Windows二进制文件版本号的首选方案。