代码之家  ›  专栏  ›  技术社区  ›  David

如何处理Python中的PyCapsule类型

  •  5
  • David  · 技术社区  · 10 年前

    我试图从

    QtGui.QWidget.effectiveWinId() 
    

    win32gui.SetWindowLong()
    

    valideWinId()正在返回:

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

    SetWindowLong()需要一个PyHANDLE(doc表示它“应该”也接受一个整数)

    TypeError: The object is not a PyHANDLE object
    

    所以我的问题是如何从PyCapsule对象中获取值,或者检查它是否为NULL?PyCapsule似乎都是C代码的内部API。

    我还发现了这个bug,它做的事情与我想要的Python的2.X PyCObject相似,而Python 3.X中不存在这个bug: http://srinikom.github.io/pyside-bz-archive/show_bug.cgi?id=523#c18

    1 回复  |  直到 10 年前
        1
  •  8
  •   David    10 年前

    好吧,我设法弄明白了:

    # ...
    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)