Python - 将字符串对象转换为ctypes(unsigned char *)

时间:2013-03-11 08:21:53

标签: python ctypes

我想使用具有以下签名的函数的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包装器中(我正在使用它作为参考)调用(也)此函数的函数具有签名:{{1 }}

    (const char * buff, const __uint32& buffLen)
  2. CDLL和WinDLL有什么区别,哪个是正确的?

1 个答案:

答案 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声明)调用约定,其中调用者清理堆栈。这允许可变函数,例如CDLLprintf用于stdcall约定,其中被调用者清理堆栈。 stdcall主要由32位Win32 API使用,例如Kernel32函数。请参阅x86 calling conventions上的维基百科文章。