问题描述
我正在尝试将翻译为Python(以及那里的其他答案)官方文档的帮助。
I'm trying to translate this SO answer code into Python (and a bit from the other answer there) with the help of official documentation for PACKAGE_ID and PACKAGE_INFO.
我通过 GetPackageFullName
得到完整的软件包名称,但是我的某些结构却不如 OpenPackageInfoByFullName
给出了对我来说毫无用处的Unicode字符。同样, PackageIdFromFullName
在调用时也会返回ERROR_INSUFFICIENT_BUFFER。
I'm getting full package names by GetPackageFullName
, but some of my structures aren't formed well as OpenPackageInfoByFullName
gives Unicode characters that are jibberish to me. Also PackageIdFromFullName
returns ERROR_INSUFFICIENT_BUFFER when called.
编辑:与注意到,我的代码存在PACKAGE_INFO_REFERENCE问题。现在我在构造缓冲区时遇到了转换缓冲区的问题,或者在此之前弄乱了一些东西。我提供了要在Windows 10中运行的代码,应先运行Edge或Store应用程序(或打开某些其他应用程序并更改代码中的硬编码文本)。输出显示packageName(作为示例字段)为None:
EDIT: As Paul Cornelius noticed, my code had issues with PACKAGE_INFO_REFERENCE. Now I have a problem converting buffer I got to structure or I messed up something before that. I provided a code to be run in Windows 10, Edge or Store app should be open prior to run (or open some other app and change the hardcoded text in code). The output shows that packageName (as the example field) is None:
import ctypes
import ctypes.wintypes
from win32api import OpenProcess, CloseHandle
from win32con import PROCESS_QUERY_INFORMATION, PROCESS_VM_READ
from win32gui import EnumChildWindows, EnumWindows
from win32process import GetWindowThreadProcessId
ERROR_SUCCESS = 0x0
ERROR_INSUFFICIENT_BUFFER = 0x7A
PACKAGE_FILTER_ALL_LOADED = 0x00000000
PACKAGE_FILTER_HEAD = 0x00000010
PACKAGE_INFORMATION_FULL = 0x00000100
PROCESS_QUERY_LIMITED_INFORMATION = 0x1000
class PACKAGE_INFO_REFERENCE(ctypes.Structure):
_fields_ = [("reserved", ctypes.c_void_p)]
class PACKAGE_SUBVERSION(ctypes.Structure):
_fields_ = [
("Revision", ctypes.wintypes.ATOM),
("Build", ctypes.wintypes.ATOM),
("Minor", ctypes.wintypes.ATOM),
("Major", ctypes.wintypes.ATOM),
]
class PACKAGE_VERSION(ctypes.Union):
_fields_ = [("Version", ctypes.c_uint64), ("DUMMYSTRUCTNAME", PACKAGE_SUBVERSION)]
class PACKAGE_ID(ctypes.Union):
_fields_ = [
("reserved", ctypes.c_uint32),
("processorArchitecture", ctypes.c_uint32),
("version", PACKAGE_VERSION),
# ("VersionRevision", ctypes.wintypes.ATOM),
# ("VersionBuild", ctypes.wintypes.ATOM),
# ("VersionMinor", ctypes.wintypes.ATOM),
# ("VersionMajor", ctypes.wintypes.ATOM),
("name", ctypes.c_wchar_p),
("publisher", ctypes.c_wchar_p),
("resourceId", ctypes.c_wchar_p),
("publisherId", ctypes.c_wchar_p),
]
class PACKAGE_INFO(ctypes.Union):
_fields_ = [
("reserved", ctypes.c_uint32),
("flags", ctypes.c_uint32),
("path", ctypes.c_wchar_p),
("packageFullName", ctypes.c_wchar_p),
("packageFamilyName", ctypes.c_wchar_p),
("packageId", PACKAGE_ID),
]
def append_to_collection(element, collection):
collection.append(element)
return True
def get_children(hwnd):
children = []
try:
EnumChildWindows(hwnd, append_to_collection, children)
except:
pass
return children
def package_full_name_from_handle(handle):
length = ctypes.c_uint()
retval = ctypes.windll.kernel32.GetPackageFullName(
handle, ctypes.byref(length), None
)
assert retval == ERROR_INSUFFICIENT_BUFFER
full_name = ctypes.create_unicode_buffer(length.value + 1)
retval = ctypes.windll.kernel32.GetPackageFullName(
handle, ctypes.byref(length), full_name
)
assert retval == ERROR_SUCCESS
return full_name
def package_path_from_full_name(full_name):
length = ctypes.c_uint()
retval = ctypes.windll.kernel32.GetPackagePathByFullName(
ctypes.byref(full_name), ctypes.byref(length), None
)
assert retval == ERROR_INSUFFICIENT_BUFFER
package_path = ctypes.create_unicode_buffer(length.value)
retval = ctypes.windll.kernel32.GetPackagePathByFullName(
ctypes.byref(full_name), ctypes.byref(length), ctypes.byref(package_path)
)
assert retval == ERROR_SUCCESS
return package_path
def package_family_name_from_full_name(full_name):
length = ctypes.c_uint()
retval = ctypes.windll.kernel32.PackageFamilyNameFromFullName(
ctypes.byref(full_name), ctypes.byref(length), None
)
assert retval == ERROR_INSUFFICIENT_BUFFER
family_name = ctypes.create_unicode_buffer(length.value)
retval = ctypes.windll.kernel32.PackageFamilyNameFromFullName(
ctypes.byref(full_name), ctypes.byref(length), ctypes.byref(family_name)
)
assert retval == ERROR_SUCCESS
return family_name
def package_info_reference_from_full_name(full_name):
package_info_reference = ctypes.pointer(PACKAGE_INFO_REFERENCE())
retval = ctypes.windll.kernel32.OpenPackageInfoByFullName(
ctypes.byref(full_name), 0, ctypes.byref(package_info_reference)
)
assert retval == ERROR_SUCCESS
return package_info_reference
def package_info_buffer_from_reference(package_info_reference):
length = ctypes.c_uint(0)
count = ctypes.c_uint()
retval = ctypes.windll.kernel32.GetPackageInfo(
package_info_reference,
PACKAGE_FILTER_HEAD,
ctypes.byref(length),
None,
ctypes.byref(count),
)
assert retval == ERROR_INSUFFICIENT_BUFFER
buffer = ctypes.create_string_buffer(length.value)
retval = ctypes.windll.kernel32.GetPackageInfo(
package_info_reference,
PACKAGE_FILTER_HEAD,
ctypes.byref(length),
ctypes.byref(buffer),
ctypes.byref(count),
)
assert retval == ERROR_SUCCESS
return buffer
def get_package(hwnd):
hprocess = None
_, pid = GetWindowThreadProcessId(hwnd)
children = get_children(hwnd)
for child in children:
_, child_pid = GetWindowThreadProcessId(child)
if child_pid != pid:
# hprocess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, False, child_pid)
hprocess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, False, child_pid)
break
if hprocess is None:
return
full_name = package_full_name_from_handle(hprocess.handle)
if not (
"Microsoft.MicrosoftEdge" in full_name.value
or "Microsoft.WindowsStore" in full_name.value
):
return None
print("\n full name:", full_name.value)
package_path = package_path_from_full_name(full_name)
print(" package path:", package_path.value)
family_name = package_family_name_from_full_name(full_name)
print(" family name:", family_name.value)
package_info_reference = package_info_reference_from_full_name(full_name)
print(" info reference:", package_info_reference.contents.reserved)
package_info_buffer = package_info_buffer_from_reference(package_info_reference)
package_info = PACKAGE_INFO()
ctypes.memmove(
ctypes.addressof(package_info), package_info_buffer, ctypes.sizeof(package_info)
)
print("packageFullName:", package_info.packageFullName)
CloseHandle(hprocess)
ctypes.windll.kernel32.ClosePackageInfo(package_info_reference)
def get_windows():
hwnds = []
EnumWindows(append_to_collection, hwnds)
return hwnds
if __name__ == "__main__":
for hwnd in get_windows():
get_package(hwnd)
输出为:
(venv) C:\dev\examples>python uwp.py
full name: Microsoft.MicrosoftEdge_44.17763.1.0_neutral__8wekyb3d8bbwe
package path: C:\Windows\SystemApps\Microsoft.MicrosoftEdge_8wekyb3d8bbwe
family name: Microsoft.MicrosoftEdge_8wekyb3d8bbwe
info reference: 4128769
packageFullName: None
full name: Microsoft.WindowsStore_11805.1001.49.0_x64__8wekyb3d8bbwe
package path: C:\Program Files\WindowsApps\Microsoft.WindowsStore_11805.1001.49.0_x64__8wekyb3d8bbwe
family name: Microsoft.WindowsStore_8wekyb3d8bbwe
info reference: 6619137
packageFullName: None
我会
推荐答案
我将您的代码翻译为完整的ctypes(没有)
I "translated" your code to full ctypes (without the win32 package).
我在调试的同时进行了修补,但基本上是:
I patched alongside debugging it, but basically:
- 某些结构被声明为Union。
- 指向类型和类型的指针之间不匹配。
-
ctypes.memove
似乎还可以,但是我更喜欢< ctypes_struct> .from_buffer
(较短)。
- Some structures were declared as Union.
- Lot of mismatch between pointer to types and types.
- The
ctypes.memove
seemed ok, but I prefer<ctypes_struct>.from_buffer
instead (shorter).
在Windows 10 1903(x64)和python 3.7.0(x64)上进行了测试。
Tested on Windows 10 1903 (x64) and python 3.7.0 (x64).
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import ctypes
import ctypes.wintypes
ERROR_SUCCESS = 0x0
ERROR_INSUFFICIENT_BUFFER = 0x7A
APPMODEL_ERROR_NO_PACKAGE = 15700
PACKAGE_FILTER_ALL_LOADED = 0x00000000
PACKAGE_FILTER_HEAD = 0x00000010
PACKAGE_INFORMATION_FULL = 0x00000100
PROCESS_QUERY_LIMITED_INFORMATION = 0x1000
PROCESS_QUERY_INFORMATION = 0x0400
PROCESS_VM_READ = 0x0010
class PACKAGE_INFO_REFERENCE(ctypes.Structure):
_fields_ = [
("reserved", ctypes.c_void_p)
]
class PACKAGE_SUBVERSION(ctypes.Structure):
_fields_ = [
("Revision", ctypes.wintypes.USHORT),
("Build", ctypes.wintypes.USHORT),
("Minor", ctypes.wintypes.USHORT),
("Major", ctypes.wintypes.USHORT),
]
class PACKAGE_VERSION_U(ctypes.Union):
_fields_ = [
("Version", ctypes.c_uint64),
("DUMMYSTRUCTNAME", PACKAGE_SUBVERSION),
]
class PACKAGE_VERSION(ctypes.Structure):
_anonymous_ = ("u", )
_fields_ = [
("u", PACKAGE_VERSION_U),
]
class PACKAGE_ID(ctypes.Structure):
_fields_ = [
("reserved", ctypes.c_uint32),
("processorArchitecture", ctypes.c_uint32),
("version", PACKAGE_VERSION),
("name", ctypes.c_wchar_p),
("publisher", ctypes.c_wchar_p),
("resourceId", ctypes.c_wchar_p),
("publisherId", ctypes.c_wchar_p),
]
class PACKAGE_INFO(ctypes.Structure):
_fields_ = [
("reserved", ctypes.c_uint32),
("flags", ctypes.c_uint32),
("path", ctypes.c_wchar_p),
("packageFullName", ctypes.c_wchar_p),
("packageFamilyName", ctypes.c_wchar_p),
("packageId", PACKAGE_ID),
]
_user32 = ctypes.WinDLL("user32", use_last_error=True)
_get_windows_thread_process_id = _user32.GetWindowThreadProcessId
_get_windows_thread_process_id.argtypes = (ctypes.wintypes.HWND, ctypes.POINTER(ctypes.wintypes.DWORD))
_get_windows_thread_process_id.restype = ctypes.wintypes.DWORD
WNDENUMPROC = ctypes.WINFUNCTYPE(ctypes.wintypes.BOOL, ctypes.wintypes.HWND, ctypes.wintypes.LPARAM)
_enum_child_windows = _user32.EnumChildWindows
_enum_child_windows.argtypes = (ctypes.wintypes.HWND, WNDENUMPROC, ctypes.wintypes.LPARAM)
_enum_child_windows.restype = ctypes.wintypes.BOOL
_enum_windows = _user32.EnumWindows
_enum_windows.argtypes = (WNDENUMPROC, ctypes.wintypes.LPARAM)
_enum_windows.restype = ctypes.wintypes.BOOL
_kernel32 = ctypes.WinDLL("kernel32", use_last_error=True)
_open_process = _kernel32.OpenProcess
_open_process.argtypes = (ctypes.wintypes.DWORD, ctypes.wintypes.BOOL, ctypes.wintypes.DWORD)
_open_process.restype = ctypes.wintypes.HANDLE
_close_handle = _kernel32.CloseHandle
_close_handle.argtypes = (ctypes.wintypes.HANDLE, )
_close_handle.restype = ctypes.wintypes.BOOL
_get_package_info = _kernel32.GetPackageInfo
_get_package_info.argtypes = (
PACKAGE_INFO_REFERENCE,
ctypes.c_uint32,
ctypes.POINTER(ctypes.c_uint32),
ctypes.POINTER(ctypes.c_uint8),
ctypes.POINTER(ctypes.c_uint32)
)
_get_package_info.restype = ctypes.wintypes.LONG
_get_package_full_name = _kernel32.GetPackageFullName
_get_package_full_name.argtypes = (ctypes.wintypes.HANDLE, ctypes.POINTER(ctypes.c_uint32), ctypes.wintypes.LPCWSTR)
_get_package_full_name.restype = ctypes.wintypes.LONG
_get_package_path_by_full_name = _kernel32.GetPackagePathByFullName
_get_package_path_by_full_name.argtypes = (ctypes.wintypes.LPCWSTR, ctypes.POINTER(ctypes.c_uint32), ctypes.wintypes.LPCWSTR)
_get_package_path_by_full_name.restype = ctypes.wintypes.LONG
_package_family_name_from_full_name = _kernel32.PackageFamilyNameFromFullName
_package_family_name_from_full_name.argtypes = (
ctypes.wintypes.LPCWSTR,
ctypes.POINTER(ctypes.c_uint32),
ctypes.wintypes.LPCWSTR)
_package_family_name_from_full_name.restype = ctypes.wintypes.LONG
_open_package_info_by_full_name = _kernel32.OpenPackageInfoByFullName
_open_package_info_by_full_name.argtypes = (
ctypes.wintypes.LPCWSTR,
ctypes.c_uint32,
ctypes.POINTER(PACKAGE_INFO_REFERENCE)
)
_open_package_info_by_full_name.restype = ctypes.wintypes.LONG
_close_package_info = _kernel32.ClosePackageInfo
_close_package_info.argtypes = (
PACKAGE_INFO_REFERENCE,
)
_close_package_info.restype = ctypes.wintypes.LONG
def get_children(hwnd):
children = []
def append_to_collection(element, param):
children.append(element)
return True
func = WNDENUMPROC(append_to_collection)
_enum_child_windows(hwnd, func, 0)
return children
def package_full_name_from_handle(handle):
length = ctypes.c_uint()
ret_val = _get_package_full_name(handle, ctypes.byref(length), None)
if ret_val == APPMODEL_ERROR_NO_PACKAGE:
print(f"package_full_name_from_handle: handle {handle:#x} has no package.")
return None
full_name = ctypes.create_unicode_buffer(length.value + 1)
ret_val = _get_package_full_name(handle, ctypes.byref(length), full_name)
if ret_val != ERROR_SUCCESS:
err = ctypes.WinError(ctypes.get_last_error())
print(f"package_full_name_from_handle: error -> {str(err)}")
return None
return full_name
def package_path_from_full_name(full_name):
length = ctypes.c_uint()
retval = _get_package_path_by_full_name(full_name, ctypes.byref(length), None)
if retval != ERROR_INSUFFICIENT_BUFFER:
raise ctypes.WinError(ctypes.get_last_error())
package_path = ctypes.create_unicode_buffer(length.value)
retval = _get_package_path_by_full_name(full_name, ctypes.byref(length), package_path)
if retval != ERROR_SUCCESS:
raise ctypes.WinError(ctypes.get_last_error())
return package_path
def package_family_name_from_full_name(full_name):
length = ctypes.c_uint()
retval = _package_family_name_from_full_name(full_name, ctypes.byref(length), None)
if retval != ERROR_INSUFFICIENT_BUFFER:
raise ctypes.WinError(ctypes.get_last_error())
family_name = ctypes.create_unicode_buffer(length.value)
retval = _package_family_name_from_full_name(full_name, ctypes.byref(length), family_name)
if retval != ERROR_SUCCESS:
raise ctypes.WinError(ctypes.get_last_error())
return family_name
def package_info_reference_from_full_name(full_name):
package_info_reference = ctypes.pointer(PACKAGE_INFO_REFERENCE())
retval = _open_package_info_by_full_name(full_name, 0, package_info_reference)
if retval != ERROR_SUCCESS:
raise ctypes.WinError(ctypes.get_last_error())
return package_info_reference
def package_info_buffer_from_reference(package_info_reference):
length = ctypes.c_uint(0)
count = ctypes.c_uint()
retval = _get_package_info(
package_info_reference.contents, # package_info_reference is already a pointer. We want its content.
PACKAGE_FILTER_HEAD,
ctypes.byref(length),
None,
ctypes.byref(count),
)
if retval != ERROR_INSUFFICIENT_BUFFER:
raise ctypes.WinError(ctypes.get_last_error())
buffer = ctypes.create_string_buffer(length.value)
buffer_bytes = ctypes.cast(buffer, ctypes.POINTER(ctypes.c_uint8))
retval = _get_package_info(
package_info_reference.contents,
PACKAGE_FILTER_HEAD,
ctypes.byref(length),
buffer_bytes,
ctypes.byref(count),
)
if retval != ERROR_SUCCESS:
raise ctypes.WinError(ctypes.get_last_error())
return buffer, length
def get_package(hwnd):
pid = ctypes.wintypes.DWORD()
_get_windows_thread_process_id(
hwnd,
ctypes.byref(pid)
)
hprocess = _open_process(PROCESS_QUERY_LIMITED_INFORMATION, False, pid)
full_name = package_full_name_from_handle(hprocess)
if not full_name:
return
else:
print(full_name.value)
'''
children = get_children(hwnd)
for child in children:
child_pid = ctypes.wintypes.DWORD(0)
_get_windows_thread_process_id(child, ctypes.byref(child_pid))
if child_pid != pid:
hprocess = _open_process(PROCESS_QUERY_LIMITED_INFORMATION, False, child_pid)
break
if hprocess is None:
return
full_name = package_full_name_from_handle(hprocess)
if full_name is None:
return
if not ("Microsoft.MicrosoftEdge" in full_name.value or "Microsoft.WindowsStore" in full_name.value):
return None
'''
print("=" * 79)
print("full name: ", full_name.value)
package_path = package_path_from_full_name(full_name)
print("package path: ", package_path.value)
family_name = package_family_name_from_full_name(full_name)
print("family name:", family_name.value)
package_info_reference = package_info_reference_from_full_name(full_name)
print("info reference:", package_info_reference.contents.reserved)
package_info_buffer, length = package_info_buffer_from_reference(package_info_reference)
# size_package_info = ctypes.sizeof(PACKAGE_INFO)
# print(f"PACKAGE_INFO size: {size_package_info:#x}")
# print(f"num package info: {length.value / size_package_info}")
package_info = PACKAGE_INFO.from_buffer(package_info_buffer)
print("packageFullName:", package_info.packageFullName)
print("=" * 79)
_close_handle(hprocess)
_close_package_info(package_info_reference.contents)
def get_windows():
hwnds = []
def append_to_collection(element, param):
hwnds.append(element)
return True
func = WNDENUMPROC(append_to_collection)
_enum_windows(func, 0)
return hwnds
if __name__ == "__main__":
for hwnd in get_windows():
get_package(hwnd)
示例输出:
===============================================================================
full name: Microsoft.Windows.Cortana_1.12.3.18362_neutral_neutral_cw5n1h2txyewy
package path: C:\Windows\SystemApps\Microsoft.Windows.Cortana_cw5n1h2txyewy
family name: Microsoft.Windows.Cortana_cw5n1h2txyewy
info reference: 2882563979504
packageFullName: Microsoft.Windows.Cortana_1.12.3.18362_neutral_neutral_cw5n1h2txyewy
===============================================================================
这篇关于如何为MS Windows PACKAGE_ID和PACKAGE_INFO结构创建Python ctypes结构?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!