-
-
Notifications
You must be signed in to change notification settings - Fork 31.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ctypes should return composite types from callbacks #49960
Comments
We have an application that calls a 3rd party library that returns a "invalid result type for callback function" The error message comes from callback.c, in function AllocFunctionCallback. I think this may be a duplicate of issue bpo-1574584. I've tested this on Windows and linux; I'm including a Makefile and ------ file: Makefile ---- all: hello.dll hello.exe hello_dll.exe hello.exe: hello.h hello.c hello_main.c hello.dll: hello.h hello.c hello_dll.exe: hello.h hello.c ------ file: hello.h ---- struct helloStruct {
int i;
float f;
int i2;
int i3;
};
float fxn (struct helloStruct callback()); ------ file: hello.c ---- #include <stdio.h>
#include "hello.h"
float fxn (struct helloStruct callback()) {
struct helloStruct result = callback(); printf ("i: %d\n", result.i); ------ file: hello_main.c ---- #include <stdio.h>
#include "hello.h"
struct helloStruct callback();
int main (int argc, char **argv) {
float f;
struct helloStruct result;
printf ("Hello world\n");
f = fxn (callback);
printf ("Callback result: %f\n", f);
}
struct helloStruct callback () {
struct helloStruct result;
result.i = 10;
result.f = 3.14159;
return result;
}
int int_callback () {
return 42;
} ------ file: hello.py ---- from ctypes import cdll, c_char, c_int, c_float, Structure, CFUNCTYPE,
POINTER, c_char_p
class helloStruct (Structure):
pass
helloStruct._fields_ = [
('i', c_int),
('f', c_float) ]
def callback():
print ("callback()")
hs = helloStruct()
hs.i = 10
hs.f = 25.5
return hs
libc = cdll.msvcrt
#helloLib = libc.load_library("hello")
#helloLib = libc.hello
helloLib = cdll.hello
helloLib.fxn.restype = helloStruct
# It looks like only simple return types are supported for
# callback functions. simple = c_int, c_float, ...
# Python bug # 1574584 - status: closed.
# Suggests posting to ctypes-users, but I don't see any recent activity.
#
TMP_FCN = CFUNCTYPE (POINTER(c_char)) # Error message
#TMP_FCN = CFUNCTYPE (c_char_p) # Runs, but invalid result
#TMP_FCN = CFUNCTYPE (c_void_p) # Runs, but invalid result
#TMP_FCN = CFUNCTYPE (c_int) # Runs, but invalid result
#TMP_FCN = CFUNCTYPE (POINTER(c_int)) # Error message
#TMP_FCN = CFUNCTYPE (POINTER(helloStruct)) # Error message
#TMP_FCN = CFUNCTYPE (helloStruct) # Error message
callback_fcn = TMP_FCN (callback)
result = helloLib.fxn (callback_fcn) # 2.5 |
There is a problem returning arbitrary complicated ctypes types from However, the callback function result will be used by some other code In principle it should be possible to make code like this work; one |
But isn't this purely a user-side concern? For example, if I want to use a function such as QBuffer::setBuffer in Returning a pointer from a function is always tough, even in C: |
I agree with Amaury that this is purely a user side concern. While I think it's important to note the behaviour of ctypes in the case that Thomas describes, I believe it's more important to fully support the range of behaviours allowed by C function callbacks. I see the use cases for complex return types that don't fall under the concerns raised by Thomas as the following:
Because I need this for my current project I will work on writing a patch. |
Any update here? |
In the example code, the 'result' variable is declared on the stack in the callback() function. So it will be effectively when callback() returns. Also the "result" variable in main() is never referenced. A pointer main()'s "result" variable should be passed to callback() as an argument ("&result") and
|
oops - I hate waking up at 4:15a. |
For those interested, we developed a workaround for this in Rubicon: https://github.com/pybee/rubicon-objc/pull/85/files The fix involves using ctypes to access ctypes own internals, and build a modified version of the Structure data type that is able to perform a copy when used as returned value. Hopefully we'll be able to get this into the form of a patch for ctypes that is acceptable to Python core. |
A follow up - the Rubicon patch has been updated to account for the changes to ctypes introduced in Python 3.13.0a6, and to account for the resolution of #81061. https://github.com/beeware/rubicon-objc/blob/main/src/rubicon/objc/ctypes_patch.py |
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields:
The text was updated successfully, but these errors were encountered: