python ctypes调用C++ dll,arry(数组)的相关操作

@[TOC](python ctypes调用C++ dll,arry(数组)的相关操作)

前言

本人新手python一枚,最近工作中需要用到python 调用C++库,一个数组调用,花费了太多时间,遂决定记录下来,防止忘记。

调用原型:

#MAX_ID_LEN_PER_THREAD 65
DWORD QueryConnectedDeviceList(int *iChNum,char szDevList[][MAX_ID_LEN_PER_THREAD],int itimeout)

C++下使用:

char devList[32][65]={0};
int iChNum=0;
res=QueryConnectedDeviceList(&iChNum,devList,30);

使用python提供的ctypes库调用C++,如果想直接看结果,请拉到最后。

这部分讨论 ctypes.Arry的个人理解

首先是官方的资料,读完一脸懵逼。ctypes

class ctypes.Array(*args)
Abstract base class for arrays.

The recommended way to create concrete array types is by multiplying any ctypes data type with a positive integer. Alternatively, you can subclass this type and define _length_ and _type_ class variables. Array elements can be read and written using standard subscript and slice accesses; for slice reads, the resulting object is not itself an Array.

_length_
A positive integer specifying the number of elements in the array. Out-of-range subscripts result in an IndexError. Will be returned by len().

_type_
Specifies the type of each element in the array.

Array subclass constructors accept positional arguments, used to initialize the elements in order.

然后网上找了一些资料,尝试了一下,如下是可以生成一个数组

def make_array(ctype,arr)->ctypes.Array:
    return (ctype * len(arr))(*arr) 

第一次我想到的是用char*的数组调用dll,能成功调用并放回正确值,但当我访问数组的值却发生了异常。
代码如下:

# -*- coding: utf-8 -*-
from ctypes import *
def make_array(ctype,arr):
    return (ctype * len(arr))(*arr)

lib = CDLL("./UCCommonLib.dll")  # 加载动态库,LoadLibrary
# note:ctypes调用和返回值默认为int --》即没有特别需要,DWORD返回类型不需要特定指定返回类型
# 如果类型不为int,则必须指定类型
lib.QueryConnectedDeviceList.argtypes =[POINTER(c_int),c_char_p * 32,c_int]
ChNum = c_int(0)
arr = [b""]*32
szDevList = make_array(c_char_p,arr)
print(szDevList)
print(szDevList[0])
res = lib.QueryConnectedDeviceList(byref(ChNum),szDevList,30)
print("res:",res)
print("ChNum:",ChNum.value)
print(szDevList)
print(szDevList[0])
print("调用完成")

运行结果:

<__main__.c_char_p_Array_32 object at 0x00E393D0>
b''
res: 0
ChNum: 2
<__main__.c_char_p_Array_32 object at 0x00E393D0>

Process finished with exit code -1073741819 (0xC0000005)

调用C++ dll前szDevList[0]是可以访问,调用后再打印szDevList[0]就报错了,无奈pycharm在ctypes下不能用debug模式,就只能自己去猜问题出在哪里。

1.怀疑是make_array方法没能生成一个以65 char字节对齐的数组,因为我生成的是一个32数组大小的char *。

按照这个想法,我直接生成一个 65 * 32 *sizeof(char) 大小的数组去调用。

# -*- coding: utf-8 -*-
from ctypes import *
def make_array(ctype,arr):
    return (ctype * len(arr))(*arr)

lib = CDLL("./UCCommonLib.dll")  # 加载动态库,LoadLibrary
lib.QueryConnectedDeviceList.argtypes =[POINTER(c_int),c_char_p ,c_int]
ChNum = c_int(0)
szDevList = create_string_buffer(b"\0", 65*sizeof(c_char) * 32)
print(szDevList)
res = lib.QueryConnectedDeviceList(byref(ChNum),szDevList,30)  
print(szDevList)
print(szDevList.raw)
print(szDevList.value)
print("调用完成")

结果:

<ctypes.c_char_Array_2080 object at 0x01819418>
QueryConnectedDeviceList
find device info:COM-1|3
find device info:COM-1|4
szDevList:COM-1|3
szDevList:COM-1|4
<ctypes.c_char_Array_2080 object at 0x01819418>
b'COM-1|3\x00\x00\x00\x00\x00\x00\x00\x00COM-1|4\x00\x00\x00\x00' # 此次省略掉若干输出
b'COM-1|3'
调用完成

我本身需要的是 szDevList包含 COM-1|3、COM-1|4两个信息,如果我使用

print(szDevList[65].raw)
output:
Traceback (most recent call last):
  File "ucdebugger.py", line 69, in <module>
    print(szDevList[65].raw)
AttributeError: 'bytes' object has no attribute 'raw'

这又会让我进入另个坑中。

再次静下心来,认真分析

def make_array(ctype,arr):
    return (ctype * len(arr))(*arr)
 
 __main__.c_char_p_Array_32 object at 0x00E393D0
 ctypes.c_char_Array_2080 object at 0x01819418

我得到了重要的结论:
def make_array(ctype,arr)->ctypes.Array
ctype * len(arr) 返回一个ctypes类型的数组, (*arr)则是构造这个类型的一个实例

c_int * 5 返回一个 c_long_Array_5类型,即 int[5]
list = [1,2,3,4,5]
(c_int * 5)(*list) 即构造了一个实列对象,即 int a[5] = {1,2,3,4,5}

按照这个想法,我开始构造二维数组。

arrType = (c_char * 65) * 32
print(arrType)
output:
c_char_Array_65_Array_32

看到这个输出,就知道该怎么做了,以下是完整代码

# -*- coding: utf-8 -*-
import ctypes
from ctypes import *

# note:ctypes调用返回值默认为int --》即没有特别需要,DWORD返回类型不需要特定指定返回类型
def make_array(ctype,arr)->ctypes.Array:
    return (ctype * len(arr))(*arr)

lib = CDLL("./UCCommonLib.dll")  # 加载动态库,LoadLibrary
arrType = (c_char * 65) * 32
print(arrType)
lib.QueryConnectedDeviceList.argtypes =[POINTER(c_int),arrType,c_int]
ChNum = c_int(0)
str65 = create_string_buffer(b"0", 65*sizeof(c_char))
arr = [str65]*32
szDevList = make_array(c_char*65,arr)
print(szDevList)
res = lib.QueryConnectedDeviceList(byref(ChNum),szDevList,30)  
print("res:",res)
print("ChNum:", ChNum.value)
# print(values.raw)
for one in szDevList:
    print(one.value)
print("调用完成")

结果:

<class '__main__.c_char_Array_65_Array_32'>
<__main__.c_char_Array_65_Array_32 object at 0x01EB95C8>
QueryConnectedDeviceList
find device info:COM-1|3
find device info:COM-1|4
szDevList:COM-1|3
szDevList:COM-1|4
res: 0
ChNum: 2
b'COM-1|3'
b'COM-1|4'
b'0'
b'0'
b'0'
b'0'
b'0'
b'0'
b'0'
b'0'
b'0'
b'0'
b'0'
b'0'
b'0'
b'0'
b'0'
b'0'
b'0'
b'0'
b'0'
b'0'
b'0'
b'0'
b'0'
b'0'
b'0'
b'0'
b'0'
b'0'
b'0'
b'0'
调用完成

Process finished with exit code 0

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值