Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布

VerQueryValueW问题python 3

在使用 Python 3 调用 Windows API 函数 VerQueryValueW 时,可能会遇到各种问题。VerQueryValueW 是 Windows 提供的一个用于查询版本资源信息的函数,通常用于读取可执行文件(如 .exe.dll)的版本信息。本文将详细介绍如何正确地在 Python 3 中使用 VerQueryValueW,并解决可能遇到的问题。

​1. 理解 VerQueryValueW 函数​

VerQueryValueW 是 Windows API 的一部分,定义在 version.h 中,并通过 version.dll 实现。它的主要功能是从版本资源中提取特定的信息,如文件版本、产品版本、公司名称等。

​函数原型​

代码语言:javascript
复制
BOOL VerQueryValueW(
  const LPVOID pBlock,
  LPCWSTR      lpSubBlock,
  LPVOID       *lplpBuffer,
  PUINT        puLen
);
  • pBlock​: 指向版本资源数据的指针。
  • lpSubBlock​: 指定要查询的子块路径,例如 \StringFileInfo\040904B0\FileDescription
  • lplpBuffer​: 指向接收查询结果的缓冲区指针的指针。
  • puLen​: 接收查询结果的长度。

返回值:

  • 如果成功,返回 TRUE
  • 如果失败,返回 FALSE,可以通过 GetLastError() 获取错误代码。

​2. 在 Python 中调用 VerQueryValueW

要在 Python 中调用 VerQueryValueW,可以使用 ctypes 库来加载 version.dll 并定义相应的函数原型。

​步骤概述​

  1. 加载 version.dll
  2. 定义 VerQueryValueW 函数的原型。
  3. 获取文件的版本信息块。
  4. 使用 VerQueryValueW 查询特定的子块。

​详细实现​

​(1) 加载 version.dll 并定义函数原型​

代码语言:javascript
复制
import ctypes
from ctypes import wintypes, create_string_buffer, byref, POINTER, Structure

# 加载 version.dll
version = ctypes.WinDLL('version.dll')

# 定义 VerQueryValueW 函数原型
VerQueryValueW = version.VerQueryValueW
VerQueryValueW.argtypes = [
    wintypes.LPCVOID,  # pBlock
    wintypes.LPCWSTR,  # lpSubBlock
    POINTER(wintypes.LPVOID),  # lplpBuffer
    POINTER(wintypes.UINT)     # puLen
]
VerQueryValueW.restype = wintypes.BOOL

​(2) 获取文件的版本信息块​

要获取版本信息块,首先需要调用 GetFileVersionInfoSizeWGetFileVersionInfoW 函数。

代码语言:javascript
复制
# 定义 GetFileVersionInfoSizeW 函数原型
GetFileVersionInfoSizeW = version.GetFileVersionInfoSizeW
GetFileVersionInfoSizeW.argtypes = [wintypes.LPCWSTR, POINTER(wintypes.UINT)]
GetFileVersionInfoSizeW.restype = wintypes.UINT

# 定义 GetFileVersionInfoW 函数原型
GetFileVersionInfoW = version.GetFileVersionInfoW
GetFileVersionInfoW.argtypes = [wintypes.LPCWSTR, wintypes.DWORD, wintypes.DWORD, wintypes.LPCVOID]
GetFileVersionInfoW.restype = wintypes.BOOL

def get_version_info_block(file_path):
    # 获取版本信息块的大小
    size = GetFileVersionInfoSizeW(file_path, None)
    if size == 0:
        raise ctypes.WinError(ctypes.get_last_error())
    
    # 分配缓冲区
    ver_block = create_string_buffer(size)
    
    # 获取版本信息块
    if not GetFileVersionInfoW(file_path, 0, size, ver_block):
        raise ctypes.WinError(ctypes.get_last_error())
    
    return ver_block

​(3) 查询特定的子块​

使用 VerQueryValueW 查询特定的子块,例如 \StringFileInfo\040904B0\FileDescription

代码语言:javascript
复制
# 定义 VerQueryValueW 函数原型(已在上面定义)

def query_version_info(ver_block, sub_block):
    buffer = ctypes.POINTER(wintypes.LPVOID)()
    length = wintypes.UINT()
    
    success = VerQueryValueW(ver_block, sub_block, byref(buffer), byref(length))
    if not success:
        raise ctypes.WinError(ctypes.get_last_error())
    
    # buffer.contents 指向实际的数据
    # 对于字符串数据,需要进一步处理
    # 这里假设返回的是字符串
    # 注意:实际情况可能需要根据子块类型进行不同的处理
    # 例如,对于 StringFileInfo,通常返回的是宽字符字符串
    
    # 由于 VerQueryValueW 返回的缓冲区指针指向的数据结构复杂,
    # 直接解析较为困难,推荐使用现成的库如 `pefile``pywin32`
    
    # 这里仅作演示,实际应用中建议使用更高级的接口
    return buffer, length

​注意​​:直接解析 VerQueryValueW 返回的缓冲区较为复杂,尤其是对于 StringFileInfo 等结构化数据。推荐使用更高级的库来简化操作。

​3. 使用现成的库简化操作​

虽然可以通过 ctypes 调用 VerQueryValueW,但手动解析版本信息块较为繁琐。Python 社区提供了一些现成的库,可以更方便地读取版本信息。

​(1) 使用 pefile 库​

pefile 是一个用于解析 Windows PE 文件(如 .exe.dll)的库,可以方便地提取版本信息。

​安装 pefile

代码语言:javascript
复制
pip install pefile

​示例代码​

代码语言:javascript
复制
import pefile

def get_version_info_pefile(file_path):
    try:
        pe = pefile.PE(file_path)
        
        if hasattr(pe, 'VS_VERSIONINFO'):
            for entry in pe.VS_VERSIONINFO:
                if hasattr(entry, 'StringFileInfo'):
                    for string_table in entry.StringFileInfo:
                        for string_entry in string_table.entries.items():
                            print(f"{string_entry[0]}: {string_entry[1]}")
        else:
            print("No version information found.")
    except pefile.PEFormatError as e:
        print(f"Error parsing PE file: {e}")

# 使用示例
get_version_info_pefile("C:\\Path\\To\\Your\\File.exe")

​优点​​:

  • 简单易用,无需手动解析复杂的结构。
  • 支持多种版本信息字段。

​(2) 使用 pywin32 库​

pywin32 提供了对 Windows API 的更高级封装,可以更方便地调用 VerQueryValueW

​安装 pywin32

代码语言:javascript
复制
pip install pywin32

​示例代码​

虽然 pywin32 没有直接封装 VerQueryValueW,但可以通过 win32api 和其他模块间接实现。不过,对于版本信息,pefile 更为直接和简便。

​4. 常见问题及解决方法​

​问题 1:VerQueryValueW 返回 False,且 GetLastError() 返回错误代码​

​可能原因​​:

  • 版本信息块未正确获取。
  • 子块路径格式不正确。
  • 文件不包含版本信息。

​解决方法​​:

  1. 确认文件确实包含版本信息(可以通过资源管理器查看属性中的详细信息)。
  2. 确保子块路径格式正确,例如 \StringFileInfo\040904B0\FileDescription
    • 0409 表示英语(美国),04B0 是代码页。
    • 可以通过解析 VarFileInfo\Translation 获取正确的代码页。
  3. 检查缓冲区分配和函数调用是否正确。

​问题 2:手动解析 VerQueryValueW 返回的缓冲区复杂​

​解决方法​​:

  • 使用现成的库如 pefile,避免手动解析复杂的结构。

​问题 3:编码问题导致字符串显示不正确​

​可能原因​​:

  • 版本信息中的字符串可能是 Unicode,而解析时未正确处理编码。

​解决方法​​:

  • 确保以正确的编码(如 UTF-16)读取字符串。
  • 使用 ctypes 时,可以尝试将缓冲区转换为适当的字符串类型。

​示例​​(高级,不推荐用于生产环境):

代码语言:javascript
复制
import ctypes
from ctypes import wintypes, create_string_buffer, byref, POINTER, Structure

version = ctypes.WinDLL('version.dll')

VerQueryValueW = version.VerQueryValueW
VerQueryValueW.argtypes = [
    wintypes.LPCVOID,
    wintypes.LPCWSTR,
    POINTER(wintypes.LPVOID),
    POINTER(wintypes.UINT)
]
VerQueryValueW.restype = wintypes.BOOL

GetFileVersionInfoSizeW = version.GetFileVersionInfoSizeW
GetFileVersionInfoSizeW.argtypes = [wintypes.LPCWSTR, POINTER(wintypes.UINT)]
GetFileVersionInfoSizeW.restype = wintypes.UINT

GetFileVersionInfoW = version.GetFileVersionInfoW
GetFileVersionInfoW.argtypes = [wintypes.LPCWSTR, wintypes.DWORD, wintypes.DWORD, wintypes.LPCVOID]
GetFileVersionInfoW.restype = wintypes.BOOL

def get_version_info(file_path, sub_block):
    size = GetFileVersionInfoSizeW(file_path, None)
    if size == 0:
        raise ctypes.WinError(ctypes.get_last_error())
    
    ver_block = create_string_buffer(size)
    if not GetFileVersionInfoW(file_path, 0, size, ver_block):
        raise ctypes.WinError(ctypes.get_last_error())
    
    buffer = ctypes.POINTER(wintypes.LPVOID)()
    length = wintypes.UINT()
    
    if not VerQueryValueW(ver_block, sub_block, byref(buffer), byref(length)):
        raise ctypes.WinError(ctypes.get_last_error())
    
    # 假设返回的是宽字符字符串
    # 需要根据实际情况调整
    # 这里仅作演示
    data = ctypes.cast(buffer.contents, ctypes.POINTER(ctypes.c_wchar * (length.value // 2))).contents
    return data.value

# 使用示例
try:
    file_path = r"C:\Path\To\Your\File.exe"
    sub_block = r"\StringFileInfo\040904B0\FileDescription"
    description = get_version_info(file_path, sub_block)
    print(f"File Description: {description}")
except Exception as e:
    print(f"Error: {e}")

​注意​​:上述代码假设返回的数据是宽字符字符串,并且子块路径正确。实际应用中,手动解析较为复杂,建议使用 pefile 等库。

​5. 推荐使用 pefile 库读取版本信息​

由于手动调用 VerQueryValueW 较为复杂且容易出错,推荐使用 pefile 库来读取版本信息。以下是一个完整的示例:

代码语言:javascript
复制
import pefile

def print_version_info(file_path):
    try:
        pe = pefile.PE(file_path)
        
        if hasattr(pe, 'VS_VERSIONINFO'):
            for entry in pe.VS_VERSIONINFO:
                if hasattr(entry, 'StringFileInfo'):
                    for string_table in entry.StringFileInfo:
                        for key, value in string_table.entries.items():
                            print(f"{key}: {value}")
        else:
            print("No version information found.")
    except pefile.PEFormatError as e:
        print(f"Error parsing PE file: {e}")

if __name__ == "__main__":
    file_path = r"C:\Path\To\Your\File.exe"  # 替换为你的文件路径
    print_version_info(file_path)

​输出示例​​:

代码语言:javascript
复制
FileVersion: 1.0.0.1
ProductVersion: 1.0.0.1
CompanyName: Your Company
FileDescription: Your Application
InternalName: YourApp.exe
LegalCopyright: Copyright © 2024
OriginalFilename: YourApp.exe
ProductName: Your Product

​优点​​:

  • 简单易用,无需处理复杂的 API 调用。
  • 支持多种版本信息字段。
  • 自动处理编码问题。
页面内容是否对你有帮助?
有帮助
没帮助

相关·内容

Python3的编码问题

​介绍Python3中的编码问题前,第一个段落对字节、ASCII​与Unicode与UTF-8等进行基本介绍,如果不对这几种编码犯头晕,可直接跳过。...Python3中的默认编码 Python3中默认是UTF-8,我们通过以下代码: import sys sys.getdefaultencoding() 可查看Python3的默认编码。​...Python3中的​encode和decode Python3中字符编码经常会使用到decode和encode函数。特别是在抓取网页中,这两个函数用的熟练非常有好处。...前文说的Python3的默认编码是UTF-8,所以我们可以看到,Python处理这些字符的时候是以UTF-8来处理的。...最后的扩展,在网上看到的他人的问题。我们写下类似于'\u4e2d'的字符,Python3知道我们想表达什么。但是让Python读取某个文件的时候出现了'\u4e2d',是不是计算机就不认识它了呢?

1.2K10
  • Python3下map函数的问题

    今天在群里有人问题,他的Python程序在家里运行好好的,但在公司一运行,就出问题了,查来查去查不出来,于是我就把他的程序调转过来看了一下,发现又是Python2.7与Python3的问题。...下面运行结果: 请输入正整数的位数:5 54748 92727 93084 Process finished with exit code 0 但在Python3下面运行结果: 请输入正整数的位数:...下面运行结果: [9, 9, 9] Process finished with exit code 0 但在Python3下面运行结果: Process...finished with exit code 0 好吧,这就明白了,Python3下发生的一些新的变化,再查了一下文档,发现加入list就可以正常了 在Python3中,rs = map(int...,以后大家都使用Python3以下版本后,就应该不需要这样做了。

    76310

    Python3实现汉诺塔问题

    Python3实现汉诺塔问题 一、思路 二、Python3代码实现 三、总结 四、参考资料 一、思路 总结归纳为以下3步: 把x上的n-1个盘子借助z,移动到y上 把x上最下面的盘子移动到z上 最后把y...上的n-1个盘子借助x移动到,z上,大功告成 递归出口:n=1时,直接从x移动到z上 二、Python3代码实现 # Python3递归实现汉诺塔游戏 def hannota(n,x,y,z): #...中间有一个递归函数的返回出问题,都会导致最后的结果出错。 汉诺塔游戏的移动次数问题其实是一个很经典的等比数列问题。...# 执行这句时会移动 1次盘子 hannota(2,‘Y’,‘X’,‘Z’ ) # 执行这句时会移动2^2 -1 = 3次盘子 所以hannota(3,‘X’,‘Y’,‘Z’)总共移动了3+1+3=...四、参考资料 通过汉诺塔问题理解递归的精髓 递归经典案例汉诺塔 python实现 形参和实参的区别 汉诺塔 程序实现—Python 及其具体运行步骤

    72020

    Windows下python2和3共存问题

    在学习python的过程中,有人推荐2,也有人推荐3。但是,不管选择了哪一个版本,总是想着是否能2个版本同时安装并兼容使用呢? 真的可以吗? 答案是肯定的,完全没有问题。...一个比较实用的方法是,将python 3.x 下的所有命令文件名称后都添加一个3,如:python ==> python3 ? 同时删除下面这个pip文件: ?...但测试发现pip3有问题(Fatal error in launcher: Unable to create process using '”'),这是由于pip的版本太低了,升级一下就可以了: python3...经过查阅,有博主的方案解决了这个问题,即重新安装pip。...“Python 安装包需要用到包管理工具pip,但是当同时安装python2和python3的时候,pip只是其中一个版本,以下将提供一个修改方式,即重新安装两个版本的pip,使得两个python版本的

    98490

    python网络爬虫(3)python爬虫遇到的各种问题(python版本、进程等)

    import urllib2 源地址 在python3.3里面,用urllib.request代替urllib2 import urllib.request as urllib2 import cookielib...源地址 Python3中,import cookielib改成 import http.cookiejar import http.cookiejar as cookielib from urlparse...Windows没有fork调用,因此,multiprocessing需要“模拟”出fork的效果,父进程所有Python对象都必须通过pickle序列化再传到子进程去。...pickling序列化中对匿名函数的不支持,导致创建进程失败 解决方案: 修改匿名函数为普通函数 为了实现windows平台对于python多进程实现的要求,并区分是自身运行还是被调用导入而运行,加入if...出现问题的代码部分如下: 问题出现在最后一行。

    1.4K20

    Python3中文字符编码问题

    前言 最近在尝试 Python Web方面的开发尝试,框架使用的是Django,但是在读取数据库并页面展示的时候,出现了中文编码的问题。...问题 我们看下面一段代码,获取小说章节列表: def main(request): sql = "SELECT id,title FROM novel LIMIT 10;" result...执行输出: {"id": 1, "title": "第一章 秦羽"} Python3执行报错: TypeError: Object of type bytes is not JSON serializable...Python3 中可以使用 json 模块来对 JSON 数据进行编解码,它包含了两个函数: json.dumps(): 对数据进行编码。 json.loads(): 对数据进行解码。...python3中存在序列化问题: TypeError: Object of type bytes is not JSON serializable 小结 在Web开发中,这个问题真的很讨厌,中文编码来回转换

    5.5K30
    领券
    首页
    学习
    活动
    专区
    圈层
    工具
    MCP广场