Python ctypes - как обрабатывать массивы строк - PullRequest
2 голосов
/ 19 июня 2010

Я пытаюсь вызвать функцию внешней библиотеки, которая возвращает массив NULL-завершенных строк с NULL-символами .

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 ]

5 голосов
/ 19 июня 2010

После обнаружения 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
3 голосов
/ 19 июня 2010

Было бы проще, если бы вы разместили исполняемый код: получить подходящее имя тома для этого вызова немного сложно. 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)

Когда я запускаю это, все списки содержат только одно имя, но если вы дважды проверьте длину, то это все, что они содержали в возвращаемом буфере.

...