import ctypes
from ctypes.wintypes import *
class xStructure(ctypes.Structure):
def __init_subclass__(cls):
p = ctypes.POINTER(cls)
class OFFSET_VAL_II_C4(xStructure):
_fields_ = [('ValOrig', DOUBLE),
('MaxChangeVal', DOUBLE),
('ActChangeVal', DOUBLE)]
The code above results in TypeError: _type_ must have storage info
triggered by line 6 (p = ctypes.POINTER(cls)
).
However, the code below works just fine.
import ctypes
from ctypes.wintypes import *
class xStructure(ctypes.Structure):
pass
class OFFSET_VAL_II_C4(xStructure):
_fields_ = [('ValOrig', DOUBLE),
('MaxChangeVal', DOUBLE),
('ActChangeVal', DOUBLE)]
p = ctypes.POINTER(OFFSET_VAL_II_C4)
My researches into the specific TypeError suggested it is caused by an attempt to create a pointer type for something that is not a ctype. However, in this case, OFFSET_VAL_II_C4 is a subclass of ctypes.Structure (via xStructure), so should work - and does, as evidenced by the second example.
What am I missing?
(For those wondering why I want to do this, there is a reason that I am happy to elaborate, but I am well aware that the minimal code here is utterly pointless!)
In your first example, when __init_subclass__
runs for OFFSET_VAL_II_C4
, the class object (cls
) exists but _fields_
has not yet been set - because __init_subclass__
runs before the class body is fully executed. So from ctypes
's point of view, cls
is not yet a complete structure - it has no storage info thus you get this error.
Whereas in second example you're calling ctypes.POINTER()
after the structure is fully defined and _fields_
has been set - so it works fine.
If your goal is to automatically define a pointer type for each subclass, you can delay the POINTER(cls)
call until after the class is completely built. This can be done using a metaclass - a more advanced way like this -
import ctypes
from ctypes.wintypes import *
class AutoPointerMeta(type(ctypes.Structure)):
def __init__(cls, name, bases, clsdict):
super().__init__(name, bases, clsdict)
if hasattr(cls, "_fields_"):
cls.PTR = ctypes.POINTER(cls)
class xStructure(ctypes.Structure, metaclass=AutoPointerMeta):
pass
class OFFSET_VAL_II_C4(xStructure):
_fields_ = [('ValOrig', DOUBLE),
('MaxChangeVal', DOUBLE),
('ActChangeVal', DOUBLE)]
# Usage:
p = OFFSET_VAL_II_C4.PTR