Как мне построить строку Python из структуры ctype? - PullRequest
5 голосов
/ 22 февраля 2011

Я использую ctypes, и я определил эту структуру для передачи параметров

class my_struct(ctypes.Structure):
    _fields_ = [ ("buffer", ctypes.c_char * BUFSIZE),
                 ("size", ctypes.c_int )]

Затем я вызываю функцию C, используя следующий код, но я не знаю, как создать строку из структуры, которую я создал.

class Client():

    def __init__(self):
        self.__proto = my_struct()
        self.client = ctypes.cdll.LoadLibrary(r"I:\bin\client.dll")

    def version(self):
        ret = self.client.execute(ctypes.byref(self.__proto))
        my_string = self.__proto.buffer[:self.__proto.size]

Я хочу создать строку Python, используя первые n байтов буфера (буфер содержит NULL-символы, но я должен разобраться с этой ситуацией и создать строку с / 0x00 символами, если это необходимо). Присвоение

my_string = self.__proto.buffer[:self.__proto.size]

не работает, потому что обрезает строку, если появляется 0x00. Любая идея приветствуется. Заранее спасибо.

Ответы [ 2 ]

3 голосов
/ 18 марта 2011

Ваша проблема в том, что ctypes пытается создать для вас магию с char массивами, автоматически преобразуя их в строки с NUL-завершением. Вы можете обойти эту магию, используя тип ctypes.c_byte вместо ctypes.c_char и получая значение в виде строки с ctypes.string_at. Вы можете сделать доступ к члену более приятным с помощью вспомогательного свойства в классе структуры, например:

import ctypes
BUFSIZE = 1024

class my_struct(ctypes.Structure):
    _fields_ = [ ("_buffer", ctypes.c_byte * BUFSIZE),
                 ("size", ctypes.c_int )]

    def buffer():
        def fget(self):
            return ctypes.string_at(self._buffer, self.size)
        def fset(self, value):
            size = len(value)
            if size > BUFSIZE:
                raise ValueError("value %s too large for buffer",
                                 repr(value))
            self.size = size
            ctypes.memmove(self._buffer, value, size)
        return property(fget, fset)
    buffer = buffer()

proto = my_struct()
proto.buffer = "here\0are\0some\0NULs"
print proto.buffer.replace("\0", " ")
0 голосов
/ 27 февраля 2011

Я думаю, вам нужно отправить указатель на строку C в my_struct, а не на строку C напрямую, потому что строки C заканчиваются нулем.Попробуйте сделать это так:

import ctypes

BUFSIZE = 10

class my_struct(ctypes.Structure):
    _fields_ = [ ("buffer", ctypes.POINTER(ctypes.c_char)),
                 ("size", ctypes.c_int )]

cstr = (ctypes.c_char * BUFSIZE)()
proto = my_struct(cstr)
...