myLibrary.resolve
is undefined, but the general code you need (untested) is:
import ctypes
dll = ctypes.CDLL('your.dll')
Open = dll.Open
Open.argtypes = [ctypes.POINTER(ctypes.c_void_p), ctypes.c_char_p]
Open.restype = ctypes.c_uint16
Handle = ctypes.c_void_p()
result = Open(ctypes.byref(Handle), 'c:\\Config.xml')
ctypes exports the byref() function which is used to pass parameters by reference. The same effect can be achieved with the pointer() function, although pointer() does a lot more work since it constructs a real pointer object, so it is faster to use byref() if you don’t need the pointer object in Python itself:,Sometimes a C api function expects a pointer to a data type as parameter, probably to write into the corresponding location, or if the data is too large to be passed by value. This is also known as passing parameters by reference.,Both of these factory functions are called with the result type as first argument, and the callback functions expected argument types as the remaining arguments.,Here is a more advanced example, it uses the strchr function, which expects a string pointer and a char, and returns a pointer to a string:
>>> from ctypes import *
>>> print(windll.kernel32)
<WinDLL 'kernel32' , handle ... at ...>
>>> print(cdll.msvcrt)
<CDLL 'msvcrt' , handle ... at ...>
>>> libc = cdll.msvcrt
>>>
>>> cdll.LoadLibrary("libc.so.6")
<CDLL 'libc.so.6' , handle ... at ...>
>>> libc = CDLL("libc.so.6")
>>> libc
<CDLL 'libc.so.6' , handle ... at ...>
>>>
>>> from ctypes import *
>>> libc.printf
<_FuncPtr object at 0x...>
>>> print(windll.kernel32.GetModuleHandleA)
<_FuncPtr object at 0x...>
>>> print(windll.kernel32.MyOwnFunction)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "ctypes.py", line 239, in __getattr__
func = _StdcallFuncPtr(name, self)
AttributeError: function 'MyOwnFunction' not found
>>>
/* ANSI version */
HMODULE GetModuleHandleA(LPCSTR lpModuleName);
/* UNICODE version */
HMODULE GetModuleHandleW(LPCWSTR lpModuleName);
>>> getattr(cdll.msvcrt, "??2@YAPAXI@Z") <
_FuncPtr object at 0x... >
>>>
>>> cdll.kernel32[1]
<_FuncPtr object at 0x...>
>>> cdll.kernel32[0]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "ctypes.py", line 310, in __getitem__
func = _StdcallFuncPtr(name, self)
AttributeError: function ordinal 0 not found
>>>
You should be passing in a string.,I'm having difficulty with how to pass the anycodings_ctypes pointer to the method:,Test computer processing speed with a simple Python script,How do I convert a currency string to a floating point number in Python?
I am trying to call the following C++ method anycodings_ctypes from my python code:
TESS_API TessResultRenderer * TESS_CALL TessTextRendererCreate(const char * outputbase) {
return new TessTextRenderer(outputbase);
}
Is following the right way?
textRenderer = self.tesseract.TessTextRendererCreate(ctypes.c_char)
or should I be doing:
outputbase = ctypes.c_char * 512 textRenderer = self.tesseract.TessTextRendererCreate(ctypes.pointer(outputbase))
For example:
self.tesseract.TessTextRendererCreate('/path/to/output/file/without/extension')
Here's a generalized example with a mock anycodings_ctypes API. In lib.cc:
#include <iostream>
extern "C" {
const char * foo (const char * input) {
std::cout <<
"The function 'foo' was called with the following "
"input argument: '" << input << "'" << std::endl;
return input;
}
}
Compile the shared library using:
clang++ - fPIC - shared lib.cc - o lib.so
Instead of using a Python string, we use a char pointer (the string equivalent) from ctypes. Hence it worked! Every ctype datatype has a value attribute, which returns a native python object. Hence we were able to return a string from the char pointer (which is basically C’s version of a string).,C++ and C both make use of Pointers, but Pointers are not available as a datatype in Python. The ctypes library gives ctypes.POINTER, which we can use to create a pointer in Python. ,Do try and use ctypes datatypes as much as possible instead of Python types when writing code which is meant to interact with C. Very few Python types can directly be used with C (without any errors), among-st which two are integers and bytes (byte strings). ,There are alternate techniques that we can use to call functions that we will discuss in this Python ctypes tutorial.
Now let’s try to import a basic library with a single function over to our Python program using ctypes. You can’t link your regular .c
file though. You need to generate a shared library, which can be done with the following command.
gcc - fPIC - shared - o clibrary.so clibrary.c
#include <stdio.h>
void prompt()
{
printf("hello world\n");
}
import ctypes
libObject = ctypes.CDLL('clibrary.so')
hello world
#include <stdio.h>
void prompt(int num)
{
printf("The number %d was entered", num);
}
#include <stdio.h>
void prompt()
{
printf("hello world\n");
}
import ctypes
libObject = ctypes.CDLL('clibrary.so')
libObject = ctypes.CDLL('clibrary.so')
libObject.prompt()
#include <stdio.h>
void prompt(int num)
{
printf("The number %d was entered", num);
}
import ctypes
testlib = ctypes.CDLL('clibrary.so')
testlib.prompt(20)
The ctypes module handles type conversions between Python and C types. In this case, the module passes the underlying Python client as the first argument of the C function. The two Python strings are passed as NULL-terminated char * arrays.,The ctypes module provides a standard AMPS::Client to these functions. Although the Client has been created by Python code, there is nothing Python-specific about the object within the C++ function. You can use the Client just as you would any other Client object.,Once you’ve compiled the library, you use the ctypes module to load the library. You then create an instance of the message handler wrapper, and pass that wrapper to the AMPS client methods, as shown below:,Once you’ve compiled the library, you use the ctypes module to load the library. You can then call the function directly from Python, using the name of the C function and passing the appropriate arguments.
extern "C"
void my_message_handler(
AMPS::Message & message,
void * userdata
);
import ctypes import AMPS ... # assumes that client is already created and connected # load the shared object dll = ctypes.CDLL("./libmymessagehandler.so") # create a handler that points to the underlying C function # and bind the user data to that handler. handler = AMPS.CMessageHandler(dll.my_message_hander, "user data") # handler can be used anywhere you would use a message handler client.subscribe(handler, "myTopic") client.set_last_chance_message_handler(handler) # and so it goes
extern "C"
void configure_client(AMPS::Client & client);
extern "C"
void publish_data(
AMPS::Client & client,
const char * topic,
const char * data
);
extern "C"
void install_server_chooser(AMPS::HAClient & client);
extern "C"
void publish_message(AMPS::Client & client,
const char * topic,
const char * data) {
try {
if ( & client && topic && data) {
client.publish(topic, data);
}
} catch (AMPS::Exception & e) {
/* Handle error reporting and recovery logic */
}
}
01 How to get value of char pointer from Python code wtih ctypes ,Aside from that, you need to set the argtypes and restype on lib.div, or Python won't know how to pass arguments correctly.,In Python, you'll also need to declare the argument types, or Python will marshal the values to C as c_int by default, which will break double and may break char* depending on the pointer implementation of your OS:,Python is a high level general purpose programming language with wide ranges of uses, from data science, machine learning, to complex scientific computations and various other things. One of the simplest of languages to get started with and as powerful as to power intelligent machines. One of the best things about python is that it is easier to get started with.
To return a value as an output parameter, you need to pass a pointer to the value type returned. Just like you used double*
to receive a double, you need a char**
to receive a char*
:
#ifdef _WIN32 # define API __declspec(dllexport) #else # define API #endif #define OK 0 #define ERROR - 1 API int div(double x, double y, char ** ppMsg, double * pOut) { static char * err_msg = "0 div error"; if (y == 0) { * ppMsg = err_msg; return ERROR; } * pOut = x / y; return OK; }
In Python, you'll also need to declare the argument types, or Python will marshal the values to C as c_int
by default, which will break double
and may break char*
depending on the pointer implementation of your OS:
from ctypes
import *
lib = CDLL('test')
lib.div.argtypes = c_double, c_double, POINTER(c_char_p), POINTER(c_double)
lib.div.restype = c_int
errmsg = c_char_p()
result = c_double()
rtn = lib.div(10, 0, byref(errmsg), byref(result))
if rtn < 0:
print(errmsg.value)
else:
print(result.value)
Output:
b '0 div error'
A pointer to the memory area of the array as a Python integer. This memory area may contain data that is not aligned, or not in correct byte-order. The memory area may not even be writeable. The array flags and data-type of this array should be respected when passing this attribute to arbitrary C-code to avoid trouble that can include Python crashing. User Beware! The value of this attribute is exactly the same as self._array_interface_['data'][0].,(c_intp*self.ndim): A ctypes array of length self.ndim where the basetype is the same as for the shape attribute. This ctypes array contains the strides information from the underlying array. This strides information is important for showing how many bytes must be jumped to get to the next element in the array.,If the ctypes module is not available, then the ctypes attribute of array objects still returns something useful, but ctypes objects are not returned and errors may be raised instead. In particular, the object will still have the as_parameter attribute which will return an integer equal to the data attribute.,This attribute creates an object that makes it easier to use arrays when calling shared libraries with the ctypes module. The returned object has, among others, data, shape, and strides attributes (see Notes below) which themselves return ctypes objects that can be used as arguments to a shared library.
>>> import ctypes
>>> x = np.array([[0, 1], [2, 3]], dtype=np.int32)
>>> x
array([[0, 1],
[2, 3]], dtype=int32)
>>> x.ctypes.data
31962608 # may vary
>>> x.ctypes.data_as(ctypes.POINTER(ctypes.c_uint32))
<__main__.LP_c_uint object at 0x7ff2fc1fc200> # may vary
>>> x.ctypes.data_as(ctypes.POINTER(ctypes.c_uint32)).contents
c_uint(0)
>>> x.ctypes.data_as(ctypes.POINTER(ctypes.c_uint64)).contents
c_ulong(4294967296)
>>> x.ctypes.shape
<numpy.core._internal.c_long_Array_2 object at 0x7ff2fc1fce60> # may vary
>>> x.ctypes.strides
<numpy.core._internal.c_long_Array_2 object at 0x7ff2fc1ff320> # may vary