我想使用具有以下签名的函数的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
很高兴得到任何帮助..
另外 - 两个简短的问题:
以下是正确的定义,假定在此DLL的现有C包装器中(我正在使用它作为参考)调用(也)此函数的函数具有签名:{{1 }}
(const char * buff, const __uint32& buffLen)
答案 0 :(得分:0)
如果你拥有的只是Python字符串,并且你确信isImageValid
不会修改其内容,那么你可以将buff
参数声明为类型c_char_p
。缓冲区内容不会被复制。
_type_
的{{1}}代码为'z'。在setter函数的{2.5}源代码_ctypes/cfield.c : z_set中,您会看到c_char_p
对象只使用底层的str
指针:
ob_sval
宏的定义如下:
1309 if (PyString_Check(value)) {
1310 *(char **)ptr = PyString_AS_STRING(value);
1311 Py_INCREF(value);
1312 return value;
也就是说,如果您可以阅读源文件,您可能更愿意将其读入可变缓冲区。以下是如何将内容读入ctypes #define PyString_AS_STRING(op) (((PyStringObject *)(op))->ob_sval)
数组(在2.5.4中测试):
创建要读取的测试文件:
c_char
获取>>> open('tmp.txt', 'w').write('''\
... This is a test.''')
中的文件大小,创建缓冲区并读入文件内容:
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
定义的情况下, ctypes会自动通过引用传递buffLen
。您还可以明确使用argtypes
。
byref(buffLen)
用于cdecl(C声明)调用约定,其中调用者清理堆栈。这允许可变函数,例如CDLL
。 printf
用于stdcall约定,其中被调用者清理堆栈。 stdcall主要由32位Win32 API使用,例如Kernel32函数。请参阅x86 calling conventions上的维基百科文章。