2

我想使用具有以下签名的函数的 DLL 文件 -

bool isValid = isImageValid((unsigned char *) buff, const __uint32& buffLen, 
                            int imageW, int imageH, __uint32 requiredSize);

现在, buff 必须来自一个字符串,我得到的 python 包装器相当于

pyBuff = open(someimagefile, 'rb').read()

由于 pyBuff 很大(大部分),我不想分配一个新的 c uchar 数组并复制,而是要利用原始缓冲区。基本上,抓取 pyBuff 对象的 char 缓冲区并将其作为 ctypes (c_ubyte *) 引用。

我最接近它的是:

buff = cast(pyBuff, POINTER(c_ubyte))

但我不确定这是我想要的类型。无论如何,该功能给了我以下错误

WindowsError: exception: access violation writing 0x00000000

很高兴有任何帮助..

另外 - 两个简短的问题:

  1. 下面的定义是否正确,因为在这个 DLL 的现有 C 包装器中(我正在使用它作为参考)调用(也)这个函数的函数具有签名:(const char * buff, const __uint32& buffLen)

    byref(c_ulong(len(pyBuff)) 
    
  2. CDLL 和 WinDLL 之间有什么区别,哪个是正确的使用?
4

1 回答 1

0

如果您只有 Python 字符串并且您确定isImageValid不会修改其内容,那么您可以将buff参数声明为 type c_char_p。缓冲区内容不会被复制。

_type_代码c_char_p是'z'。在 setter 函数的 2.5.4 源代码_ctypes/cfield.c : z_set中,您会看到对于一个str对象,它只使用底层ob_sval指针:

1309    if (PyString_Check(value)) {
1310        *(char **)ptr = PyString_AS_STRING(value);
1311        Py_INCREF(value);
1312        return value;

其中宏定义如下:

#define PyString_AS_STRING(op) (((PyStringObject *)(op))->ob_sval)

也就是说,如果您可以读取源文件,您可能更愿意将其读入可变缓冲区。以下是如何将内容读入 ctypesc_char数组(在 2.5.4 中测试):

创建要读取的测试文件:

>>> open('tmp.txt', 'w').write('''\
... This is a test.''')

获取 a 中的文件大小c_uint32,创建缓冲区,并读入文件内容:

>>> import os
>>> from ctypes import *
>>> buffLen = c_uint32()
>>> buffLen.value = os.path.getsize('tmp.txt')
>>> buff = (c_char * buffLen.value)()
>>> open('tmp.txt').readinto(buf)
15
>>> buff.value
'This is a test.'

关于你的另外两个问题,我会这样设置函数原型:

lib = CDLL(path_to_dll)
isImageValid = lib.isImageValid
isImageValid.argtypes = c_char_p, POINTER(c_uint32), c_int, c_int, c_uint32
isImageValid.restype = c_bool

buffLen给定上述argtypes定义, ctypes 将自动通过引用传递。您也可以显式使用byref(buffLen).

CDLL用于 cdecl(C 声明)调用约定,其中调用者清理堆栈。这允许可变参数函数,例如printf. WinDLL用于 stdcall 约定,其中被调用者清理堆栈。stdcall 主要由 32 位 Win32 API 使用,例如 Kernel32 函数。请参阅有关x86 调用约定的 Wikipedia 文章。

于 2013-03-12T06:19:38.027 回答