Embedding python in cpp: How to get a C-pointer to a python function (not to a PyObject)?

Embedding python in cpp: How to get a C-pointer to a python function (not to a PyObject)?



I want to enable the writing of user python-plugins for an existing C++ application. The main application will emit signals using boost::signals2 that trigger the execution of the users python code. I set up a working sample where an initialize method in the users python module is being called. The user can subscribe to signals calling a "connect"-method:


import ctypes
CALLBACK_VOID_FUNC = CFUNCTYPE(None)

def myVoidHandler():
print("myVoidHandler (python)")

def initialize(myCHandle):
global myCDll, callback1
myCDll = ctypes.CDLL("CppEventsd", handle = myCHandle)
[...]
callback1 = CALLBACK_VOID_FUNC(myVoidHandler)
myCDll.connect(b"readyToGo", callback1)
[...]



The signature of the connect method:


extern "C" __declspec(dllexport) bool connect(char* signalName, void(*pF)())



Now the python function myVoidHandler could be called from cpp just like this:


pF();



But more importantly, pF can be connected to a boost signal.



However I want to spare the users going through this (and spare myself the support requests because they did not get it quite right), so I want to connect the python functions from the cpp side by using a naming convention for the functions/slots.
I can easily retrieve a PyObjet pointer to the python callback:


PyObject *pModule, *pDict, *pVoidHandlerF;
pModule = PyImport_Import(pName);
pDict = PyModule_GetDict(pModule);
pVoidHandlerF = PyDict_GetItemString(pDict, "myVoidHandler");



BUT I cannot figure out how to get the actual function pointer (equivalent to pF) from the cpp side! Some transformation seems to be going on in the python to Cpp transition.



Any ideas?





Instead of connecting directly to the python function pointer, you could create your own C++ function that invokes pVoidHandlerF, for example, by using a C++ lambda: sig.connect([=]() PyObject_CallObject(pVoidHandlerF, NULL); );
– pschill
Aug 23 at 13:47



pVoidHandlerF


sig.connect([=]() PyObject_CallObject(pVoidHandlerF, NULL); );





YES! That´s the better solution anyway, because I can then also check for the return of PyObject_CallObject and print a useful message if something goes wrong! I´ll go with that.
– uha
Aug 25 at 21:02





Okay, I have moved the comment to an answer. Feel free to accept it :)
– pschill
Aug 27 at 8:26




1 Answer
1



Instead of connecting directly to the python function pointer, you could create your own C++ function that uses the python C-API to invoke the python function. Here is an example:


boost::signals2::signal<void(void)>& sig = [...];
PyObject* pVoidHandlerF = [...];
sig.connect([=]()
PyObject_CallObject(pVoidHandlerF, NULL);
);



This allows you to do other stuff on the C++ side, for example, passing arguments, returning values, checking for errors, etc.






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Popular posts from this blog

𛂒𛀶,𛀽𛀑𛂀𛃧𛂓𛀙𛃆𛃑𛃷𛂟𛁡𛀢𛀟𛁤𛂽𛁕𛁪𛂟𛂯,𛁞𛂧𛀴𛁄𛁠𛁼𛂿𛀤 𛂘,𛁺𛂾𛃭𛃭𛃵𛀺,𛂣𛃍𛂖𛃶 𛀸𛃀𛂖𛁶𛁏𛁚 𛂢𛂞 𛁰𛂆𛀔,𛁸𛀽𛁓𛃋𛂇𛃧𛀧𛃣𛂐𛃇,𛂂𛃻𛃲𛁬𛃞𛀧𛃃𛀅 𛂭𛁠𛁡𛃇𛀷𛃓𛁥,𛁙𛁘𛁞𛃸𛁸𛃣𛁜,𛂛,𛃿,𛁯𛂘𛂌𛃛𛁱𛃌𛂈𛂇 𛁊𛃲,𛀕𛃴𛀜 𛀶𛂆𛀶𛃟𛂉𛀣,𛂐𛁞𛁾 𛁷𛂑𛁳𛂯𛀬𛃅,𛃶𛁼

Edmonton

Crossroads (UK TV series)