This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: ctypes automatic byref failing on custom classes attributes
Type: enhancement Stage:
Components: ctypes Versions: Python 3.10, Python 3.9, Python 3.8
process
Status: open Resolution:
Dependencies: Superseder:
Assigned To: Nosy List: amaury.forgeotdarc, belopolsky, eryksun, lepaperwan, meador.inge
Priority: normal Keywords:

Created on 2016-08-19 18:11 by lepaperwan, last changed 2022-04-11 14:58 by admin.

Messages (4)
msg273149 - (view) Author: Erwan Le Pape (lepaperwan) * Date: 2016-08-19 18:11
When using a custom class to store a ctype value, passing that class as a function argument explicitly declared to be a pointer type fails to pass the _as_parameter_ class attribute as a pointer and instead raises a TypeError.

For example:
>>> from ctypes import *
>>> from ctypes.wintypes import *
>>>
>>> class CustomPHKEY(object):
...     def __init__(self, value):
...             self._as_parameter_ = HKEY(value)
...
>>>
>>> function = windll.function
>>> function.argtypes = [POINTER(HKEY)]
>>> function.restype = LONG
>>> result = CustomPHKEY(0)
>>> function(result)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ctypes.ArgumentError: argument 1: <type 'exceptions.TypeError'>: expected LP_c_void_p instance instead of c_void_p

Shouldn't ctypes apply the required byref() conversion automatically? Or is this behavior normal and automatic byref() only concerns native ctypes types?

I only flagged Python 3.5 and Python 2.7 since they are the only ones I explicitly tested this on but I suspect other versions are affected.
msg273711 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2016-08-26 17:54
I ran the the following, which I don't understand, and therefore don't what should happen, on Win 10, 3.6.0a3.

from ctypes import *
from ctypes.wintypes import *

class CustomPHKEY(object):
    def __init__(self, value):
        self._as_parameter_ = HKEY(value)

function = windll.function
function.argtypes = [POINTER(HKEY)]
function.restype = LONG
result = CustomPHKEY(0)
function(result)

Traceback (most recent call last):
  File "F:\Python\mypy\tem.py", line 8, in <module>
    function = windll.function
  File "C:\Programs\Python36\lib\ctypes\__init__.py", line 417, in __getattr__
    dll = self._dlltype(name)
  File "C:\Programs\Python36\lib\ctypes\__init__.py", line 347, in __init__
    self._handle = _dlopen(self._name, mode)
OSError: [WinError 126] The specified module could not be found
msg273755 - (view) Author: Eryk Sun (eryksun) * (Python triager) Date: 2016-08-27 03:33
Terry, the provided example is incomplete and doesn't make sense as it stands. For better or worse, windll.dllname attempts to load WinDLL(dllname) and cache the resulting library on the windll loader. (The library in turn caches function pointers, which means this design is a problem waiting to happen, which has happened a few times with various projects conflicting with each other over windll.kernel32 function prototypes. I recommend using WinDLL instead.)

I gather that Erwan wants ctypes.byref() and the implicit _byref that's called by PyCPointerType_from_param to be enhanced to support objects that define _as_parameter_. So I'm changing the issue type accordingly.
msg273868 - (view) Author: Erwan Le Pape (lepaperwan) * Date: 2016-08-29 15:55
I can confirm Eryk got what I meant. I didn't know if it was meant to work that way or if it was simply something that was overlooked so I thought I'd ask, I will look into the ctypes code to provide a patch sometime this week if I can.

Terry, for a working example take the following (on a MS Windows):
>>> from ctypes import *
>>> from ctypes.wintypes import *
>>>
>>> class CustomPHKEY(object):
...     def __init__(self, value):
...             self._as_parameter_ = HKEY(value)
...
>>>
>>> function = ctypes.windll.advapi32.RegOpenKeyExW
>>> function.argtypes = [HKEY, c_wchar_p, DWORD, DWORD, POINTER(HKEY)]
>>> function.restype = LONG
>>> result = CustomPHKEY(0)
>>> function(0x80000002, 'SOFTWARE', 0, 0x20019, result)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ctypes.ArgumentError: argument 5: <type 'exceptions.TypeError'>: expected LP_c_void_p instance instead of c_void_p
History
Date User Action Args
2022-04-11 14:58:35adminsetgithub: 71990
2021-03-05 19:59:59terry.reedysetnosy: - terry.reedy
2021-03-05 16:00:34eryksunsetversions: + Python 3.8, Python 3.9, Python 3.10, - Python 2.7, Python 3.5
2016-08-29 15:55:22lepaperwansetmessages: + msg273868
2016-08-27 03:33:38eryksunsettype: behavior -> enhancement

messages: + msg273755
nosy: + eryksun
2016-08-26 17:54:26terry.reedysetnosy: + terry.reedy
messages: + msg273711
2016-08-19 18:11:37lepaperwancreate