객체 지향 Python에서 ctypes를 사용하여 DLL 파일에서 함수를 실행하는 중에 문제가 발생했습니다.

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

문제

나는 이것이 이미 답변된 질문이나 어리석은 질문이 아니기를 바랍니다.최근에는 여러 악기를 사용하여 프로그래밍을 하고 있습니다.테스트 프로그램을 만들기 위해 그들 사이의 통신을 시도합니다.그러나 계측기 DLL 파일에서 "마스킹"한 함수를 호출하려고 할 때 특정 계측기에서 몇 가지 문제가 발생했습니다.대화형 Python 셸을 사용하면 완벽하게 작동합니다(단어가 너무 많아도).하지만 객체 지향 방식으로 함수를 구현하면 프로그램이 실패합니다. 실제로는 실패하지 않고 아무것도 하지 않습니다.이것이 호출되는 첫 번째 방법입니다.(ctypes 및 ctypes.util을 가져옴)

    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

이제 작동이 원활해졌고 모든 것이 완벽해졌으며 완벽한 로그 항목을 얻었습니다.그러나 프로그램 내에서 메소드를 추가로 실행하려고 하면 다음과 같이 호출됩니다.

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)

프로그램이 갑자기 작동을 멈추거나 계속 실행됩니다. "self.maury" 라인이 호출될 때 아무 일도 일어나지 않습니다.init_hardware 메소드에 모든 것을 배치하면 완벽하게 작동하므로 약간의 메모리 "오류"나 객관적인 구조에 뭔가가 있는 것 같습니다.정말 이런 식으로 유지하고 싶습니다. 어쨌든 이런 방식으로 기능을 분리할 수 있나요?아니면 큰 코드 덩어리로 제한해야 합니까?


편집하다:
문서 정보:
[전설:별은 포인터를 나타내고 괄호는 배열을 나타냅니다.]

add_tuner 함수는 튜너 드라이버 객체에 하나의 튜너를 추가하거나 업데이트합니다.

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

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



add_controller 함수는 튜너 드라이버 객체에 하나의 컨트롤러를 추가하거나 업데이트합니다.

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

산출: error_string, function-return->Error flag

도움이 되었습니까?

해결책 3

내보낸 DLL에서 함수를 호출하는 유일한 방법은 각 메서드의 매개 변수를 통해 DLL을 사용하는 것임을 알게 되었습니다.(프로그램은 dll을 내보내고 호출된 각 메서드에서 이를 매개변수로 보냅니다.)그것은 꽤 추악해 보이지만 그것이 내가 나를 위해 일하는 유일한 방법이라고 생각합니다.DLL을 클래스 속성으로 내보내려고도 했습니다.제가 작업하고 있는 시스템은 꽤 무거워서 어딘가에 시스템이 실패하게 만드는 보부 코드가 있는 것 같습니다.모든 피드백과 팁에 감사드립니다!

/마즈닥

다른 팁

정확한 문제가 무엇인지 잘 모르겠지만 다음은 몇 가지 일반적인 팁입니다.

생성자 외부에서 호출하는 함수의 경우 해당 함수를 설정하는 것이 좋습니다. argtypes 생성자에서도 마찬가지입니다.일단 선언하면 argtypes, 모든 인수를 다음과 같이 캐스팅할 필요는 없습니다. c_short, c_double, 등.더욱이 실수로 C 함수에 잘못된 인수를 전달한 경우 Python은 DLL 내에서 충돌하는 대신 런타임 오류를 발생시킵니다.

또 다른 사소한 세부 사항이지만 사용해야 합니다. x = 0; byref(x) 아니면 어쩌면 POINTER(c_double)() 튜너와 컨트롤러의 포인터(c_double()) 대신.

저는 최근 Python 2.6에서 일부 ctypes 클래스를 작성해 왔지만 귀하가 설명하는 것과 같은 문제는 본 적이 없습니다.분명히 그것에 대한 Python 버그 보고서도 없기 때문에 문제가 있는 귀하의 방법에서 우리 둘 다 간과하고 있는 아주 작은 세부 사항이 있다고 강력히 믿습니다.

add-controller 또는 add-tuner의 매개변수 중 실제로 값을 반환하는 매개변수가 있습니까?

모든 매개변수의 캐스트를 사용하여 함수를 직접 호출하는 것보다 함수의 프로토타입을 정의하는 것이 좋습니다.

나는 당신이 이미 이 페이지를 읽었을 것이라고 확신합니다, 하지만 보고 싶은 섹션은 함수 프로토타입입니다.코드를 훨씬 더 깔끔하고 쉽게 추적/디버깅할 수 있습니다.

또한 - Mark Rushakoff도 언급했듯이 - 호출에서 포인터(c_double())를 사용하는 것은 꽤 이상합니다.POINTER()를 사용하면 훨씬 더 나은 행운을 누릴 수 있으므로 값을 변수로 미리 선언하고 함수 호출에 변수를 전달하는 것이 좋습니다.그런 다음 적어도 나중에 이상한 동작에 대한 값을 검사할 수 있습니다.

편집하다:따라서 프로토타입과 호출은 다음과 같습니다.

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)

그러면 통화가 훨씬 깔끔해집니다.

arg1 = 0
arg2 = 0
arg3 = 0
AddController(tuner_number, self.file_path, name, arg1, arg2, arg3, 
    serial_number, self.error_string)
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top