【问题标题】:How to deal with PyCapsule type inside Python如何在 Python 中处理 PyCapsule 类型
【发布时间】:2014-03-19 05:46:26
【问题描述】:

我正在尝试从

传递对象
QtGui.QWidget.effectiveWinId() 

win32gui.SetWindowLong()

effectiveWinId() 正在返回:

<capsule object NULL at 0x027C9BF0>
<class 'PyCapsule'>

并且 SetWindowLong() 需要一个 PyHANDLE(文档说它“应该”也接受一个整数)

TypeError: The object is not a PyHANDLE object

所以我的问题是如何从 PyCapsule 对象中获取值或检查其是否为 NULL?看来 PyCapsule 是 C 代码的所有内部 API。

我还发现这个错误与我想要的 Python 2.X PyCObject 的功能相似,而 Python 3.x 中不存在此错误:http://srinikom.github.io/pyside-bz-archive/show_bug.cgi?id=523#c18

【问题讨论】:

  • 我的平台是 Windows 7/8 32-bit Python-3.3 和最新的 PySide。
  • 2.X 错误的链接无效...这是一个有效的链接:link。我已经使用 ctypes.pythonapi.PyCObject_AsVoidPtr 东西处理了这个问题,并且正在寻找 Python 3.2+ 修复程序。

标签: python winapi pyside python-c-api


【解决方案1】:

好的,我设法弄明白了:

# ...
capsule = self.effectiveWinId()
ctypes.pythonapi.PyCapsule_GetPointer.restype = ctypes.c_void_p
ctypes.pythonapi.PyCapsule_GetPointer.argtypes = [ctypes.py_object, ctypes.c_char_p]
handle = ctypes.pythonapi.PyCapsule_GetPointer(capsule, None)
win32gui.SetWindowLong(handle, win32con.GWL_WNDPROC, self.new_window_procedure)
# ...

这里有一个python类来处理覆盖win32窗口过程:

import win32con
import win32gui
import win32api
import ctypes
import pywintypes

def convert_capsule_to_int(capsule):
    ctypes.pythonapi.PyCapsule_GetPointer.restype = ctypes.c_void_p
    ctypes.pythonapi.PyCapsule_GetPointer.argtypes = [ctypes.py_object, ctypes.c_char_p]
    return ctypes.pythonapi.PyCapsule_GetPointer(capsule, None)

class WindowProcedure(object):
    self.handle_WM_DESTROY = False
    def __init__(self, handle):
        if isinstance(handle, int) or isinstance(handle, type(pywintypes.HANDLE())):
            self.handle = handle
        else:
            self.handle = convert_capsule_to_int(handle)
        self.old_proc = win32gui.GetWindowLong(self.handle, win32con.GWL_WNDPROC)
        if not self.old_proc:
            raise RuntimeError("Failed to set/get window procedure!") 
        if not win32gui.SetWindowLong(self.handle, win32con.GWL_WNDPROC, self.new_window_procedure):
            raise RuntimeError("Failed to set/get window procedure!")

    def handle_old_procedure(self, hwnd, msg, wparam, lparam):
        # For some reason the executable would hang after a QtGui.QWidget exit
        # so I'm forcing it here if self.handle_WM_DESTROY is true
        if msg == win32con.WM_DESTROY and self.handle_WM_DESTROY:
            win32gui.DestroyWindow(hwnd)
            return 0
        return win32gui.CallWindowProc(self.old_proc, hwnd, msg, wparam, lparam)

【讨论】:

  • 你是怎么想出来的? handle = ctypes.pythonapi.PyCapsule_GetPointer(capsule, None) ?谢谢你为我节省了几个小时的阅读时间。
  • @MatthewMoisen 我不得不挖掘大量的 Python 源代码来弄清楚这一点。真的没有那么有趣。很高兴我能帮上忙。
猜你喜欢
  • 1970-01-01
  • 2012-10-27
  • 2016-04-11
  • 2013-05-28
  • 2021-08-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多