Why does setting ctypes dll.function.restype = c_void_p return for a long time?

It seems strange that even after setting restype , python returns long , not c_void_p .

For instance:

 # python code from ctypes import * dll = windll.LoadLibrary("my.dll") dll.my_object_create.restype = c_void_p x = dll.my_object_create() print type(x) # prints <type 'long'> //c++ code my_object *my_object_create() { return new my_object(); } void my_object_destroy(my_object *obj) { delete obj; } 

Recently, I had to fix an error when, by feeding x back to another ctypes function, the pointer was trampled. This has been fixed by changing the initial dll call to

 x = c_void_p(dll.my_object_create()) 

... I assume that somewhere along the ctypes line x is treated as 4 bytes long, and not 8 (64-bit architecture).

So, I am wondering if there is a reason why existing behavior leads you into this trap?

+4
source share
1 answer

P_get for the 'P' pointer type uses PyLong_FromVoidPtr . If the address matches the long platform, it returns Python int ; otherwise, it returns a Python long that has variable precision. This is fine, but when passing this integer value as an argument, the default behavior is to convert to C int , which is 32-bit on all supported platforms.

I think the best solution is to set argtypes to properly convert the argument to a pointer type. Another option is to set restype to a subclass of c_void_p . Using a subclass disables conversion to a Python integer. GetResult checks this by calling _ctypes_simple_instance , which actually returns the opposite of what its name and original comment suggests. (In 2.5, this function was called IsSimpleSubType , and the original comment was erroneous even then. The β€œsimple” in the question was never a metaclass PyCSimpleType , but the base type is _SimpleCData .)

POSIX:

 # Configure the interpreter to load visible extension- # module symbols, such as _ctypes_simple_instance, # into the global symbol table. import sys, DLFCN sys.setdlopenflags((sys.getdlopenflags() & ~DLFCN.RTLD_LOCAL) | DLFCN.RTLD_GLOBAL) from ctypes import * _ctypes_simple_instance = PyDLL(None)._ctypes_simple_instance _ctypes_simple_instance.argtypes = py_object, malloc = CDLL(None).malloc class my_void_p(c_void_p): pass 
 >>> _ctypes_simple_instance(c_void_p) 0 >>> _ctypes_simple_instance(my_void_p) 1 >>> malloc.restype = c_void_p >>> type(malloc(100)) <type 'int'> >>> malloc.restype = my_void_p >>> type(malloc(100)) <class '__main__.my_void_p'> 

Window:

_ctypes_simple_instance not exported _ctypes.pyd.

 from ctypes import * malloc = cdll.msvcrt.malloc class my_void_p(c_void_p): pass 
 >>> malloc.restype = c_void_p >>> type(malloc(100)) <class 'int'> >>> malloc.restype = my_void_p >>> type(malloc(100)) <class '__main__.my_void_p'> 
+6
source

Source: https://habr.com/ru/post/1493252/


All Articles