업무 중 서드파티 프로그램을 필자의 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번째 인덱스값에 더미 데이터를 고려해야 한다.