Структурировать с другой структурой внутри, используя ctypes - PullRequest
0 голосов
/ 25 октября 2018

Я занимаюсь разработкой программного обеспечения для управления храповым механизмом, оно использует dll под названием xpcomlib и имеет примеры использования на C. Я разрабатываю на Python и использую используемую мной DLL ctypes, я смог сделать, например, те же самые потребности от одного pointeiro до одной структуры, и одна структура имеет другую.Давайте сделаем это более понятным.

Вот часть руководства:

int FAR PASCAL FXPBasicConvFromText(
  const char FAR* szFileOrig, // Source File name will be converted
  const char FAR* szFileDest, // Dest file name will be converted
  CONVFILEFORMAT FAR* pF // Pointer to source file format
);

Аргумент pF является указателем на структуру типа CONVFILEFORMAT, которая определяет формат источникафайл.cFields Количество полей в исходном файле должно быть от 1 до 10. Для каждого из полей cFields выше у нас есть структура Field, определяемая как:

CONVFILEFORMAT

struct {
   cName [11]     Field name only for conversions with destination file type DBF
   cType          Field type XPFLD_INT, XPFLD_FLO, XPFLD_STR. See XPCOMxx.H.
   cLength        Length of field
   cDec           Number of decimal places used for floating point in file conversion
XPbasic format for DBASE format
} Field [10];

Пример, сделанный в руководстве:

#include <windows.h>
#include <string.h>
#include “xpcom16.h”

char szInFile[20];
char szOutFile[20];
CONVFILEFORMAT fF;

int PASCAL WinMain(HANDLE hInstance, HANDLE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    fF.cFields = 3;
    fF.Field[0].cType = XPFLD_STR;
    fF.Field[0].cLength = 80;
    fF.Field[0].cDec = 0;
    fF.Field[1].cType = XPFLD_INT;
    fF.Field[1].cLength = 2;
    fF.Field[1].cDec = 0;
    fF.Field[2].cType = XPFLD_FLO;
    fF.Field[2].cLength = 8;
    fF.Field[2].cDec = 0;
    strcpy(szInFile, “C:\\TRIX\\ARQTXT.DAT”);
    strcpy(szOutFile, “C:\\TRIX\\ARQXPB.DAT”);
    if (FXPBasicConvFromText(szInFile, szOutFile, &fF))
        return FALSE;
    return TRUE;
}

Учитывая это, мне нужно использовать dll в python, пока я сделал это:

class ConvFileField(ctypes.Structure):
    _fields_ = [("cName", ctypes.c_char_p), ("cType", ctypes.c_byte),
                ("cLength", ctypes.c_byte), ("cDec", ctypes.c_byte)]

class Struct(ctypes.Structure):
    _fields_ = [("cFields", ctypes.c_byte), ("Field", ctypes.POINTER(ConvFileField))]

    elems = (ConvFileField * 10)()
    Field = ctypes.cast(elems, ctypes.POINTER(ConvFileField))

formatPointer = ctypes.POINTER(Struct)
formatPointer.cFields = 0 #Works
formatPointer.Field[0].cType = 1 #Doesn't work

Однако я получаю следующую ошибку, утверждая, что моя структура не содержит поля Field, а вышеприведенный cFields работает нормально.

formatPointer.Field[0].cType = 1 AttributeError: type object
'LP_Struct' has no attribute 'Field'

1 Ответ

0 голосов
/ 25 октября 2018

Имея только искаженное, частичное определение одного поля CONVFILEFORMAT, я не могу сказать вам точно, как определить тот же тип структуры в ctypes.Однако я могу ответить на общий вопрос о том, как обрабатывать структурные типы с помощью вложенных структур, массивов и массивов структур.

Поле структуры в форме

struct {
    ...
} Field [10];

является массив , а не указатель.В частности, это поле с именем Field, тип которого представляет собой массив длины 10 с анонимным структурным типом, определенным предшествующей частью struct {...}.Если ваш код ctypes определяет тип элементов Field как ConvFileField, то правильное объявление самого поля Field будет

('Field', ConvFileField*10)

в списке _fields_.Если ваш список _fields_ в противном случае является правильным (мы не можем сказать), тогда правильное объявление будет

class CONVFILEFORMAT(ctypes.Structure):
    _fields_ = [('cFields', ctypes.c_byte), ('Field', ConvFileField*10)]

Кстати, ваше поле cName в ConvFileField имеет ту же проблему.cName выглядит как массив длины 11 в фактическом C, но вместо этого вы объявили указатель.

...