我的机器是带有anaconda的Win7。 我最近将C ++ dll函数转换为python项目。 我克服了许多困难,但我不知道如何处理以下转换:
typedef int (__stdcall *p_API_GetOrder)(vector<ApiOrder>& apiOrderList);
哪里
class ApiOrder(Structure):
_fields_ = [
('Timestamp', c_long),
('Item', c_char * 16),
('Qty', c_long),
]
在python中,我尝试过
mydll.API_GetOrder(POINTER(ApiOrder()))
错误是:
TypeError: must be a ctypes type
我不是C ++或编程人员的出口商。所以不太清楚什么是byref。如果有人可以清除我的想法,那就太好了。
答案 0 :(得分:0)
POINTER(…)
构造一个新的 pointer类型,而不是该类型的值。所以,当您这样做时:
mydll.API_GetOrder(POINTER(ApiOrder()))
…您传递的是Python类型的对象,而不是C指针对象周围的ctypes包装器。
要获取指向ctypes
包装对象的指针,您需要调用pointer
或byref
。前者构造一个POINTER(…)
实例,将其设置为指向您的对象,然后传递包装的指针。后者只是直接将指针传递给您的对象,而无需构造指针包装器对象,通常这就是您所需要的。有关更多详细信息,请参见在文档中传递指针。
但是,由于两个原因,我认为这样做不会有多大好处。
首先,大多数使用指向某个结构的指针并返回int的函数都在执行此操作,以便它们可以用有用的值填充该结构。构造一个新的空结构并传递一个指向它的指针,而不保留对它的引用意味着您无法查看所填充的任何值。
此外,您可能要检查返回值。
通常,您需要执行以下操作:
order = ApiOrder()
ret = mydll.API_GetOrder(byref(order))
if ret:
do some error handling with either ret or errno
else:
so something with order
在此过程中,您几乎肯定要set the argtypes
and restype
of the function,因此ctypes
知道如何正确地转换内容,并且如果您执行的操作没有意义,则会给您一个例外。如果它猜错了,它会猜测如何转换和传递事物以及段错误。
另外,对于返回成功或错误int
的函数,通常最好将函数分配给restype
,以查找错误和raise
适当的例外。 (如果您需要的不仅仅是检查int返回非零或指针返回为零,还可以使用errcheck
。)
但是,即使这样对这里也无济于事,因为您尝试调用的函数首先没有使用指向ApiOrder
的指针,而是引用了{{1 }}个。因此,您需要调用C ++ stdlib构造一个那个类型的对象,然后可以std::vector
将该对象作为参数。
但是通常,编写一些向库提供C API的C ++代码,然后使用byref
调用该C API较容易,而不是尝试从Python构建和使用C ++对象。
您的C ++代码如下所示:
ctypes
现在,您可以通过创建1个int call_getorder(p_API_GetOrder func, ApiOrder *apiOrderArray, size_t apiOrderCount) {
std::vector<ApiOrder> vec(apiOrderArray, apiOrderCount);
ret = func(vec);
if (ret) return ret;
std::copy(std::begin(vec), std::end(vec), apiOrderArray);
return 0;
}
中的an array(或创建一个ApiOrder
到POINTER
并直接传递它(如果愿意)来从Python调用它) :
ApiOrder
当然,您仍然需要orders = (ApiOrder*1)()
ret = mywrapperdll.call_order(mydll.API_GetOrder, byref(order), 1)
if ret:
do some error handling with either ret or errno
else:
do something with order[0]
和argtypes
。