2010-06-18 109 views
2

我想调用一个外部库函数,该函数返回a NULL-terminated array of NULL-terminated stringsPython ctypes - 如何处理字符串数组

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; 
} 

回答

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 
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) 

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

+0

“这个呼叫要找一份合适的卷名是有点痛” - 'mountvol'将列出所有卷的GUID。 – grawity 2010-06-19 18:49:26

+0

“当我运行这个时,所有的列表都只包含一个名字,但如果你仔细检查长度,那么它们就包含在返回的缓冲区中。” - 几乎总是这样,是的,但是除了驱动器盘符之外,我的一些可移动驱动器可以通过Unix风格的安装点到达。无论哪种方式,我只是寻找一个通用的解决方案,不一定''GetVolume ...()' - 具体。但是'split('\ 0')'现在已经够好了。 – grawity 2010-06-19 18:50:19