I have a C/C++ dll with a function:
int get_camera_info(char * description, char * serial_number, char * manufacturer)
This function takes the arguments and modifies them, so that you could print them. I'm trying to use this DLL from Python by using ctypes
. I guess I would need to use ctypes.create_string_buffer
to create an empty buffer so that I have a mutable object. But then, how do I do so that I can pass it as an argument and then retrieve the data?
Do I need to use cast(buffer_object, c_char_p_object)
? How would this be any different from creating and passing a c_char_p
object in the first place? I don't know much about C/C++, but maybe I should be using ctypes.POINTER
.
My problem was that after passing a c_char_p
type object as an argument I'm getting the error: OSError: exception: access violation reading 0x00000000
.
If you need any help trying to understand what my question is, just ask. Or if you think I'm better off using something like cppyy, then I would need help with that too. :)
Here's the basics. Although not strictly required in this case, setting .argtypes
and .restype
correctly helps ctypes
marshal parameters correctly and detect incorrectly passed parameters.
Similar to passing arrays to C functions, create_string_buffer
returns an c_char_Array_array_size
object, but it is marshaled as a pointer to it's first element (c_char_p
) so it agrees with the .argtypes
assignment.
Without the .argtypes
assignment, passing something incorrect such as an int
or a create_unicode_buffer()
array would crash or have the wrong result. But defining it correctly would catch those errors and raise an exception.
test.c
#include <string.h>
#ifdef _WIN32
# define API __declspec(dllexport)
#else
# define API
#endif
API int get_camera_info(char * description, char * serial_number, char * manufacturer)
{
strcpy(description, "Description");
strcpy(serial_number, "12345678");
strcpy(manufacturer, "Manufacturer");
return 1;
}
test.py
from ctypes import *
MAX_STR = 256 # docs better say how big the buffers are required to be.
# int get_camera_info(char * description, char * serial_number, char * manufacturer)
dll = CDLL('./test')
dll.get_camera_info.argtypes = c_char_p,c_char_p,c_char_p
dll.get_camera_info.restype = c_int
desc = create_string_buffer(MAX_STR)
sn = create_string_buffer(MAX_STR)
mfg = create_string_buffer(MAX_STR)
ret = dll.get_camera_info(desc,sn,mfg)
print(desc.value.decode(),sn.value.decode(),mfg.value.decode())
Output:
Description 12345678 Manufacturer
Note that .value
returns a byte string at the beginning of the buffer up to the first null byte exclusive. .raw
will dump a byte string with every byte of the buffer. .decode()
converts a byte string into a Unicode string using UTF-8 as the default encoding.
User contributions licensed under CC BY-SA 3.0