python

时间:2018-08-20 14:47:37

标签: python c++ ctypes

我的机器是带有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。如果有人可以清除我的想法,那就太好了。

1 个答案:

答案 0 :(得分:0)

POINTER(…)构造一个新的 pointer类型,而不是该类型的值。所以,当您这样做时:

 mydll.API_GetOrder(POINTER(ApiOrder()))

…您传递的是Python类型的对象,而不是C指针对象周围的ctypes包装器。


要获取指向ctypes包装对象的指针,您需要调用pointerbyref。前者构造一个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(或创建一个ApiOrderPOINTER并直接传递它(如果愿意)来从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