在使用 Python 3 调用 Windows API 函数 VerQueryValueW
时,可能会遇到各种问题。VerQueryValueW
是 Windows 提供的一个用于查询版本资源信息的函数,通常用于读取可执行文件(如 .exe
或 .dll
)的版本信息。本文将详细介绍如何正确地在 Python 3 中使用 VerQueryValueW
,并解决可能遇到的问题。
VerQueryValueW
函数VerQueryValueW
是 Windows API 的一部分,定义在 version.h
中,并通过 version.dll
实现。它的主要功能是从版本资源中提取特定的信息,如文件版本、产品版本、公司名称等。
BOOL VerQueryValueW(
const LPVOID pBlock,
LPCWSTR lpSubBlock,
LPVOID *lplpBuffer,
PUINT puLen
);
pBlock
: 指向版本资源数据的指针。lpSubBlock
: 指定要查询的子块路径,例如 \StringFileInfo\040904B0\FileDescription
。lplpBuffer
: 指向接收查询结果的缓冲区指针的指针。puLen
: 接收查询结果的长度。返回值:
TRUE
。FALSE
,可以通过 GetLastError()
获取错误代码。VerQueryValueW
要在 Python 中调用 VerQueryValueW
,可以使用 ctypes
库来加载 version.dll
并定义相应的函数原型。
version.dll
。VerQueryValueW
函数的原型。VerQueryValueW
查询特定的子块。version.dll
并定义函数原型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
要获取版本信息块,首先需要调用 GetFileVersionInfoSizeW
和 GetFileVersionInfoW
函数。
# 定义 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
使用 VerQueryValueW
查询特定的子块,例如 \StringFileInfo\040904B0\FileDescription
。
# 定义 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
等结构化数据。推荐使用更高级的库来简化操作。
虽然可以通过 ctypes
调用 VerQueryValueW
,但手动解析版本信息块较为繁琐。Python 社区提供了一些现成的库,可以更方便地读取版本信息。
pefile
库pefile
是一个用于解析 Windows PE 文件(如 .exe
和 .dll
)的库,可以方便地提取版本信息。
pefile
pip install pefile
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")
优点:
pywin32
库pywin32
提供了对 Windows API 的更高级封装,可以更方便地调用 VerQueryValueW
。
pywin32
pip install pywin32
虽然 pywin32
没有直接封装 VerQueryValueW
,但可以通过 win32api
和其他模块间接实现。不过,对于版本信息,pefile
更为直接和简便。
VerQueryValueW
返回 False
,且 GetLastError()
返回错误代码可能原因:
解决方法:
\StringFileInfo\040904B0\FileDescription
。0409
表示英语(美国),04B0
是代码页。VarFileInfo\Translation
获取正确的代码页。VerQueryValueW
返回的缓冲区复杂解决方法:
pefile
,避免手动解析复杂的结构。可能原因:
解决方法:
ctypes
时,可以尝试将缓冲区转换为适当的字符串类型。示例(高级,不推荐用于生产环境):
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
等库。
pefile
库读取版本信息由于手动调用 VerQueryValueW
较为复杂且容易出错,推荐使用 pefile
库来读取版本信息。以下是一个完整的示例:
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)
输出示例:
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
优点: