Python ctypes - 如何处理字符串数组

时间:2010-06-18 22:32:29

标签: python ctypes

我正在尝试调用返回a NULL-terminated array of NULL-terminated strings的外部库函数。

kernel32 = ctypes.windll.kernel32
buf = ctypes.create_unicode_buffer(1024)
length = ctypes.c_int32()
if kernel32.GetVolumePathNamesForVolumeNameW(ctypes.c_wchar_p(volume),
    buf, ctypes.sizeof(buf), ctypes.pointer(length)):
    ## ???

换句话说:

buf = ctypes.create_unicode_buffer(u'Hello\0StackOverflow\0World!\0')

如何将buf所有内容作为Python列表访问? buf.value只能达到第一个NULL。

在C中它会是这样的:

while (*sz) {; 
    doStuff(sz);
    sz += lstrlen(sz) + 1;
}

2 个答案:

答案 0 :(得分:5)

在发现ctypes.wstring_at()ctypes.addressof()之后,我得到了这个:

def wszarray_to_list(array):
    offset = 0
    while offset < ctypes.sizeof(array):
        sz = ctypes.wstring_at(ctypes.addressof(array) + offset*2)
        if sz:
            yield sz
            offset += len(sz)+1
        else:
            break

答案 1 :(得分:3)

如果您发布了可运行代码会更容易:为此调用获取合适的卷名有点痛苦。 buf是一个包含length个字符的数组。最后两个字符为空,因此忽略它们,使用''.join()将数组转换为字符串并拆分空字符。

import ctypes
kernel32 = ctypes.windll.kernel32

def volumes():
    buf = ctypes.create_unicode_buffer(1024)
    length = ctypes.c_int32()
    handle = kernel32.FindFirstVolumeW(buf, ctypes.sizeof(buf))
    if handle:
        yield buf.value
        while kernel32.FindNextVolumeW(handle, buf, ctypes.sizeof(buf)):
            yield buf.value
        kernel32.FindVolumeClose(handle)

def VolumePathNames(volume):
    buf = ctypes.create_unicode_buffer(1024)
    length = ctypes.c_int32()
    kernel32.GetVolumePathNamesForVolumeNameW(ctypes.c_wchar_p(volume),
        buf, ctypes.sizeof(buf), ctypes.pointer(length))
    return ''.join(buf[:length.value-2]).split('\0')

for volume in volumes():
    print volume
    print VolumePathNames(volume)

当我运行这个时,所有列表只包含一个名称,但如果你仔细检查长度,那么它们包含在返回的缓冲区中。