Python에서 Visual Basic .NET dll 사용 (pythonnet)

업무 중 서드파티 프로그램을 필자의 Python 프로그램에서 호출해야 할 일이 생겼다.
문제는 서드파티 프로그램이 Visual Basic .NET으로 만들어졌다는 것
그나마 다행인 건 해당 프로그램 제조사에서 dll 파일을 함께 제공해주었다는 점인데
일반적인 C dll 파일과 달리 .NET의 dll파일은 다루기가 까다롭다는 이야기를 들은 기억이 있다.

아니나다를까 C dll 파일처럼 ctypes 패키지를 통한 호출이 불가능했다.
포팅해야 하는 코드도 양이 무척 많아서 불안에 떨던 중 pythonnet이라는 훌륭한 패키지를 발견했다.
이 패키지는 Python과 .NET Common Language Runtime (CLR)를 통합해주며 Python에서 .Net을, 그리고 그 반대를 실행할 수 있게 해준다.

런타임이니만큼 코드 정적분석이 되지 않아 에러 메시지를 계속 안고 가야 하는 문제점은 있지만
서드파티를 간단히 연동할 수 있다는 점을 생각한다면 충분히 안고 갈 만한 문제이다.

사용 방법은 단순하다.

import clr

clr.AddReference('xxx.dll')
from Namespace import MyClass
my_class = MyClass()

그 이후의 활용은 ctypes에서처럼 사용하면 된다.

필자는 FAA에서 제공하는 ACR 계산 프로그램을 연동하는데 pythonnet을 사용했는데
시행착오를 위해 내용을 공유한다.

1. ACRClassLib.dll 다운로드 후 로드

  • 공개된 소스코드 상에는 네임스페이스가 없어 상당히 애를 먹었다.
  • 혹시나 싶어 파일명을 네임스페이스로 설정하니 연동이 잘 되었다.
clr.AddReference(Conf.RESOURCE_DIR + 'ACRClassLib.dll')
from ACRClassLib import clsACR
acr = clsACR()

2. 클래스로부터 함수 사용

  • dll에 정의된 규격대로 파라미터를 넣어주면 함수가 정상적으로 실행된다.
  • 중요한 점은 구조체나 배열을 넘겨줄 때이다.
  • 구조체의 경우 동일한 규격의 구조체를 만들어 넘겨주어야하며 (ctypes를 참고하면 좋다)
  • 배열의 경우 포인터 형태로 넘겨주어야 한다.
def test(self):
    from ACRClassLib import clsACR
    pavement_type = clsACR.PavementType.Rigid
    gross_weight = 400000.0
    percent_gw = 0.475
    wheels_number = 4
    tire_pressure = 200.0
    coord_x = [0.0, -15.0, 15.0, -15.0, 15.0]
    coord_y = [0.0, 0.0, 0.0, 55.0, 55.0]
    sw = [1, 1, 1, 1, 1]
    metric = False

    result = self.acr.CalculateACR(pavement_type,
                                   gross_weight,
                                   percent_gw,
                                   wheels_number,
                                   tire_pressure,
                                   (c.c_float * len(coord_x))(*coord_x),
                                   (c.c_float * len(coord_y))(*coord_y),
                                   (c.c_int * len(sw))(*sw),
                                   metric)

    for i in range(1, 5):
        print(result.libACR[i])
        print(result.libACRthick[i])
        print(result.libSubCat[i])
        print(result.libSubCatMPa[i])

특히 VB의 경우 인덱싱을 1부터 하기 때문에 배열의 입출력 시 반드시 0번째 인덱스값에 더미 데이터를 고려해야 한다.

댓글 남기기