Problema executando funções de um arquivo DLL usando ctypes em Python orientada a objetos

StackOverflow https://stackoverflow.com/questions/1170372

Pergunta

Espero que isso não será uma questão já respondida ou um estúpido. Recentemente eu tenho programado com vários instrumentos. Tentando se comunicar entre eles, a fim de criar um programa de testes. No entanto eu encoutered alguns problemas com um instrumento específico quando eu estou tentando chamar funções que eu "mascarados" para fora dos instrumentos arquivo DLL. Quando eu uso o python interativo desembolsar ele funciona perfeitamente (embora seu um monte de palavra clobbering). Mas quando eu implementar as funções de uma maneira orientada a objeto o programa falhar, bem, na verdade ele não falha simplesmente não fazer nada. Este é o primeiro método que é chamado: (ctypes e ctypes.util é importado)

    def init_hardware(self):
    """ Inits the instrument """
    self.write_log("Initialising the automatic tuner")
    version_string = create_string_buffer(80)
    self.error_string = create_string_buffer(80)
    self.name = "Maury MT982EU"
    self.write_log("Tuner DLL path: %s", find_library('MLibTuners'))
    self.maury = WinDLL('MlibTuners')
    self.maury.get_tuner_driver_version(version_string)
    if (version_string.value == ""):
        self.write_log("IMPORTANT: Error obtaining the driver version")
    else:
        self.write_log("Version number of the DLL: %s" % version_string.value)
    self.ThreeTypeLong = c_long * 3

Agora que as obras inchar, tudo é perfeito e eu fico perfeitos log-entradas. Mas quando tento executar um método mais para o programa chamado:

def add_tuner_and_controller(self, name, serial_number, tuner_number=0):
    """ Adds the tuner to the driver object, controller is inside the tuner """
    self.write_log("Adding tuner %d and the built-in controller" % tuner_number)
    TempType = self.ThreeTypeLong()
    self.maury.add_controller(c_short(tuner_number), c_char_p(self.file_path), c_char_p(name), c_int(0), c_int(0), 
                              c_long(0), c_short(serial_number), self.error_string)
    self.maury.add_tuner(c_short(tuner_number), c_char_p(name), c_short(serial_number), c_short(0),
                            c_short(1), pointer(c_double()), TempType, pointer(c_double()), pointer(c_double()),
                            pointer(c_double()), self.error_string)

O programa de repente pára de funcionar / continua correndo, happenes nada quando o "self.maury" -line é chamado. Quando eu colocar tudo no método init_hardware ele funciona perfeitamente, então eu estou supondo que há uma ligeira memória "erro" ou algo com a estrutura orientada objetivo. Eu realmente quero que ele permaneça desta forma, há de qualquer maneira para isolar as funções dessa maneira? ou eu tenho que me restringir a um grande pedaço de código?


EDIT:
info Documentação :
[Legenda: As estrelas indicam ponteiros e os colchetes indicam matrizes]

A função add_tuner acrescenta ou atualizações de um sintonizador no objeto driver do sintonizador.

short add_tuner(short tuner_number, char model[ ], short serial_number, short ctlr_num, short ctlr_port, short *no_of_motors, long max_range[ ], double *fmin, double *fmax, double *fcrossover, char error_string[ ])

saída : no_motors, max_range (array of three numbers), fmin, fmax, fcrossover,error_string (80+ characters long), function-return->Error flag



A função add_controller adiciona ou atualiza um controlador no objeto driver do sintonizador

short add_controller(short controller_number, char driver[ ], char model[ ], int timeout, int address, long delay_ms, char error_string[ ])

saída : error_string, function-return->Error flag

Foi útil?

Solução 3

Eu descobri que a única maneira de chamar as funções na DLL exportada era usar a DLL através de um parâmetro em cada método. (O programa exporta a dll e em cada método chamado ele vai enviá-lo como um parâmetro). Parece muito feio, mas essa é a única maneira que encontrei para estar a trabalhar para mim. Eu até tentei exportar a DLL como um atributo classe. O sistema que eu estou trabalhando com é bastante robusto então eu acho que há alguma em algum lugar boboo-código que faz com que seja falhar. Obrigado por todos os comentários e sugestões!

/ Mazdak

Outras dicas

Eu não tenho certeza sobre o seu problema exato, mas é aqui algumas dicas gerais:

Para as funções que você está chamando fora do construtor, eu recomendo fortemente definindo sua argtypes no construtor também. Uma vez que você declarou o argtypes, você não deve precisar para lançar todos os argumentos como c_short, c_double, etc. Além disso, se você acidentalmente passar um argumento incorreto para uma função C, Python irá aumentar um erro de execução em vez de bater dentro a DLL.

Outro detalhe menor, mas você deve estar usando x = 0; byref(x) ou talvez POINTER (c_double)() em vez de ponteiro (c_double ()) no sintonizador e controlador.

Eu tenho escrito algumas classes ctypes em Python 2.6, recentemente, bem como, e eu não vi qualquer problema como o que você está descrevendo. Uma vez que há, aparentemente, não existem quaisquer relatórios de bugs Python em que qualquer um, eu acredito fortemente que não há apenas um detalhe minucioso que estamos ambos com vista para em seu método que está tendo um problema.

Algum dos parâmetros add-controller ou add-sintonizador realmente valores de retorno?

Recomendamos que você define protótipos de suas funções, em vez de chamá-los de dirigir com moldes de todos os parâmetros.

eu tenho certeza que você já leu esta página já , mas a seção você quer é olhar para protótipos de função. Torna o código muito mais limpo e mais fácil de traço / debug.

Além disso - como Mark Rushakoff menciona também - usando ponteiro (c_double ()) e como em sua chamada é muito nojento. Eu tenho muita sorte melhor w / Pointer (), e recomendar novamente que você predeclare o valor como uma variável, e passar a variável em sua chamada de função. Então, pelo menos você pode examinar o seu valor depois de um comportamento estranho.

EDIT: Então o seu protótipo e chamada será algo parecido com isto:

prototype = WINFUNCTYPE(
    c_int,              # Return value (correct? Guess)
    c_short,            # tuner_number
    c_char_p,           # file_path
    c_char_p,           # name
    c_int,              # 0?
    c_int,              # 0?
    c_long,             # 0?
    c_short,            # serial_number
    c_char_p,           # error_string
)
# 1 input, 2 output, 4 input default to zero (I think; check doc page)
paramflags = (1, 'TunerNumber' ), (1, 'FilePath' ), (1, 'Name' ), ...
AddController = prototype(('add_controller', WinDLL.MlibTuners), paramflags)

Em seguida, a sua chamada é muito mais limpo:

arg1 = 0
arg2 = 0
arg3 = 0
AddController(tuner_number, self.file_path, name, arg1, arg2, arg3, 
    serial_number, self.error_string)
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top