Ant*_*ony 2 c python windows ctypes
尝试创建一个python回调,需要在Windows环境中从dll调用C回调时调用它.请查看以下代码以了解该问题.
from ctypes import *
#---------qsort Callback-------------#
IntArray5 = c_int * 5
ia = IntArray5(5,1,7,33,99)
libc = cdll.msvcrt
qsort = libc.qsort
qsort.restype = None
CMPFUNC = CFUNCTYPE(c_int,POINTER(c_int),POINTER(c_int) )
test = 0
def py_cmp_func(a,b):
#print 'py_cmp_func:',a[0],b[0]
global test
test = 10000
return a[0]-b[0]
cmp_func = CMPFUNC(py_cmp_func)
qsort(ia, len(ia), sizeof(c_int), cmp_func)
print "global test=",test
for item in ia : print item
#----------Load DLL & Connect ------------#
gobiDLL = WinDLL("C:\LMS\QCWWAN2k.dll")
print 'Output of connect : ',gobiDLL.QCWWANConnect()
#----------SetByteTotalsCallback----------#
tx = POINTER(c_ulonglong)
rx = POINTER(c_ulonglong)
proto_callback = WINFUNCTYPE(c_void_p,tx,rx)
gtx = grx = 0 # Used to copy the response in the py_callback
def py_callback(t,r):
sleep(10)
print 'python callback ...'
print "tx=",t,"rx=",r
global gtx,grx
gtx = 5000 # gtx = t
grx = 2000 # grx = r
#return 0
callback = proto_callback(py_callback)
gobiDLL.SetByteTotalsCallback.restype = c_ulong
gobiDLL.SetByteTotalsCallback.argtypes = [proto_callback,c_byte]
print "SetByteTotalsCallback = ",gobiDLL.SetByteTotalsCallback(callback, c_byte(256))
print "gtx = ",gtx
print "grx = ",grx
Run Code Online (Sandbox Code Playgroud)
DLL记录Prototype和SetByteTotalsCallback()方法的回调,如下所示.
原型:
ULONG QCWWANAPI2K SetSessionStateCallback( tFNSessionState pCallback );
Run Code Online (Sandbox Code Playgroud)
打回来 :
void ByteTotalsCallback( ULONGLONG txTotalBytes, ULONGLONG rxTotalBytes );
Run Code Online (Sandbox Code Playgroud)
输出:
>>>
global test= 10000
1
5
7
33
99
Output of connect : 0
SetByteTotalsCallback = 0
gtx = 0
grx = 0
>>>>
Run Code Online (Sandbox Code Playgroud)
目前的问题是整个程序被正确调用,但python回调根本没有被调用.该程序从gobiDLL.SetByteTotalsCallback(回调,c_byte(256))方法退出0状态,但在调用期间不调用用python编写的callback()方法.
你能指出什么可以帮助进入python回调?另一个示例qsort()方法奇妙地将指针传递给python函数指针.无法在这里找到问题的根本原因.
TIA,
安东尼
小智 6
你不能.C/C++函数无法直接访问Python函数 - 函数原型可能需要指向C的指针.Python将向其传递指向其特定函数的内部数据结构的指针.
这是构建python的C扩展以包装该DLL并将其暴露给Python的时候.你要做的就是用C回调调用Python回调,因为可以做到.更清楚的是,您想要实现的目标是:
| This side is C land i.e. "real" addresses
|
Python objects --> C extension -- register callback with --> DLL
| |
in the python | Calls callback
| |
interpreter <-------------- Callback in C extension <-------
|
Run Code Online (Sandbox Code Playgroud)
以下是从C构建调用python函数的一个非常快速的解释.您需要使用用于构建Python发行版的MSVC(或替代工具)来构建此代码; 使用depends.exe找出哪些msvcXX.dll是对链接.
全局状态通常被认为是坏的,但为了简单起见,我使用的是:
static PyObject* pyfunc_event_handler = NULL;
static PyObject* pyfunc_event_args = NULL;
Run Code Online (Sandbox Code Playgroud)
然后我添加了一个set handler函数,以便更容易地设置回调.但是,您不需要这样做,您只需要
static PyObject* set_event_handler(PyObject *self, PyObject *args)
{
PyObject *result = NULL;
PyObject *temp;
Run Code Online (Sandbox Code Playgroud)
下一行是重要的一行 - 我允许传递两个python对象(O参数为PyArg_ParseTuple.一个对象包含函数,另一个包含其参数.
if (PyArg_ParseTuple(args, "OO", &temp, &pyfunc_event_args)) {
if (!PyCallable_Check(temp)) {
PyErr_SetString(PyExc_TypeError, "parameter must be a function");
return NULL;
}
Run Code Online (Sandbox Code Playgroud)
整理参考.Python需要你这样做.
Py_XINCREF(temp); /* Add a reference to new func */
Py_XDECREF(pyfunc_event_handler); /* Dispose of previous callback */
pyfunc_event_handler = temp; /* Remember new callback */
/* Boilerplate to return "None" */
Py_INCREF(Py_None);
result = Py_None;
}
return result;
}
Run Code Online (Sandbox Code Playgroud)
然后你可以在其他地方调用它:
PyObject* arglist = Py_BuildValue("(O)", pyfunc_event_args);
pyobjresult = PyObject_CallObject(pyfunc_event_handler, arglist);
Py_DECREF(arglist);
Run Code Online (Sandbox Code Playgroud)
别忘了DECREF,你需要Python来gc arglist.
从python中,使用它就像这样简单:
set_event_handler(func, some_tuple)
Run Code Online (Sandbox Code Playgroud)
其中func具有匹配的参数,如下所示:
def func(obj):
/* handle obj */
Run Code Online (Sandbox Code Playgroud)
您可能想要阅读的内容:
| 归档时间: |
|
| 查看次数: |
3418 次 |
| 最近记录: |