Search code examples
pythonwinapictypespywin32win32gui

How to send a Python list as argument by reference to EnumChildWindows using the ctypes module?


I have the following working Python code that uses the module win32gui to call the EnumChildWindows function:

import win32gui

def func(hwnd, param):
  param.append(hwnd)
  return True

def code():
  arr = []
  win32gui.EnumChildWindows(win32gui.GetDesktopWindow(), func, arr)
  print(arr)

code()

win32gui.EnumChildWindows allows to pass, by reference, any Python object in the last argument.

I'm trying to do the same using the module ctypes. The closest I have gotten is passing a C array instead of the Python list, though it's not passing by reference because when I change the variable inside the function it doesn't change its value outside.

Code below:

from ctypes import byref, POINTER, windll, WINFUNCTYPE
from ctypes.wintypes import BOOL, HWND, LPARAM

def func(hwnd, param):
  c_arr = HWND * (len(param) + 1)
  param = c_arr(*param)
  param[len(param) - 1] = hwnd
  print(str(param[len(param) - 1]))
  return True

def code():
  py_arr = []
  c_arr = HWND * len(py_arr)
  arr = c_arr(*py_arr)
  WNDENUMPROC = WINFUNCTYPE(BOOL, HWND, HWND * len(py_arr))
  windll.user32.EnumChildWindows.argtypes = [HWND, WNDENUMPROC, POINTER(HWND * len(py_arr))]
  windll.user32.EnumChildWindows.restype = BOOL
  windll.user32.EnumChildWindows(windll.user32.GetDesktopWindow(), WNDENUMPROC(func), byref(arr))
  print(arr)

code()

Solution

  • After a while of searching and trying different things, I found the code of win32gui in C.

    It uses PyObject which corresponds to ctypes.py_object.

    Working code below:

    from ctypes import byref, py_object, windll, WINFUNCTYPE
    from ctypes.wintypes import BOOL, HWND
    
    def func(hwnd, param):
      param.append(hwnd)
      return True
    
    def code():
      arr = []
      WNDENUMPROC = WINFUNCTYPE(BOOL, HWND, py_object)
      windll.user32.EnumChildWindows.argtypes = [HWND, WNDENUMPROC, py_object]
      windll.user32.EnumChildWindows.restype = BOOL
      windll.user32.EnumChildWindows(windll.user32.GetDesktopWindow(), WNDENUMPROC(func), arr)
      print(arr)
    
    code()