간만에 글을 올립니다. 이번 주에는 상당히 바쁘게 한 주일을 보내는 바람에 블로그를 남기지 못했습니다. 그래서 이번 주에 제가 작업한 내용을 좀 끄적거려 볼려구 합니다.
삽질의 개요
이번 주에 애를 먹었던 부분은 ChartFX의 라이센스 문제였습니다. 지금 제가 관여된 프로젝트는 소위 스마트 클라이언트를 이용한 프로젝트인데, 여기서 말하는 스마트 클라이언트는 IE 웹 브라우저 안에 닷넷으로 작성한 UserControl을 띄워 UI를 구현하는 것을 말합니다. 머 쉽게 생각하면 개발 환경은 닷넷이고 브라우저 안에 ActiveX 와 같은 방법으로 UI를 개발하는 거죠.
그런데... 이 스마트 클라이언트 시나리오상에서 윈폼(WinForm)용 ChartFX가 항상 라이센스 오류를 발생한다는 것이였습니다. 원래 ChartFX와 같은 컨트롤 제품들은 개발자 라이센스 기반이어서 개발할 때만 설치해 주면 배포는 자유롭게 할 수 있기 때문에 ChartFX가 설치되지 않은 사용자 컴퓨터에서도 ChartFX의 DLL들이 스마트 클라이언트 기반 기술(MS 에서는 No-Touch-Deployment 라 부릅니다)에 의해 다운로드 되면 라이센스 문제 없이 정상 작동해야 하는 거죠. 게다가 동일한 스마트 클라이언트 시나리오에서 동일한 버전 !!!(6.2.1342.0)의 ChartFX를 1년 전에 S 기업에서 이미 사용을 했었고 그때는 약간의 삽질 끝에 별 문제 없이 해결을 했었다는 겁니다.
삽질의 시작
이번주 초인가요...(폭소 클럽 버전. 모르면 말고... -_-) 출근을 떡 해보니 ChartFX 라이센스 문제가 있다는 보고를 받았습니다. 속으론 내심 '아하~ 그거...' 하면서 S 기업에서 한대로 하면 되겠지 하며 대수롭지 않게 생각했습니다. 그런데... 웬걸... 1년 전 S 기업에서 했던 방법대로 아무리 해도 ChartFX는 런타임 라이센스를 읽을 수 없다며 오류를 찍찍 뱉어 내곤 했습니다.
1년전에 했던것 처럼 SoftwareFX(ChartFX 개발사) 사이트를 가서 뒤져보니 역시 1년전 자료가 아무런 변화 없이 그대로 남아 있더군요. SoftwareFX 자료 왈, "ChartFX를 사용하는 코드가 DLL 이라면 DLL 이 아닌 EXE에 라이센스 정보가 포함되어 컴파일 되어야 한다." 이 말은 1년 전에도 본 내용이고, 1년 전에 해결했던 방식대로 ChartFX를 사용하는 DLL을 로드하는 DLL (메뉴 컨트롤이 있는 DLL 입죠)의 license.licx 파일에 라이센스 정보를 넣었습니다만 여전히 오류가 발생하는 것이였습니다.
드디어 저의 삽질은 시작되었습니다. System.ComponentModel 네임스페이스에 있는 라이센스 관련 클래스들(LicenseManager, LicenseContext, RuntimeLicenseContext 클래스 등)의 코드를 까보기 시작했습니다. 그리고 ChartFX DLL의 소스도 까봐야 했죠.
크~헉~. ChartFX DLL은 Ofuscator가 사용되어 Non-Public 멤버들의 이름이 죄다 맹글링(mangling)되어 코드 보기가 대략 뷁스러웠습니다. 그래도 코드를 추적하고 심지어 어셈블리 언어(기계어 코드. 닷넷의 어셈블리가 아님) 수준까지 디버깅 하면서 결론에 도달한 것은... 닷넷 프레임워크(적어도 버전 1.1에서는)와 ChartFX가 공히 Entry Assembly에 기록된 라이센스 정보만을 읽는다는 것을 알아 냈습니다. 하지만 스마트 클라이언트 시나리오에서는 Entry Assembly가 지정되지 않는다는 문제가 있었죠. 그래서 ChartFX가 자꾸 라이센스 오류를 뱉어 낸 겁니다.
불가능은 없다... 대략 귀찮을 뿐...
이를 해결하기 위해서는 ChartFX의 라이센스 확인 루틴을 우회해야 했습니다. ChartFX는 Entry Assembly의 존재 유무를 확인하고, 만약 Entry Assembly가 존재하지 않는 다면, 레지스트리에서 라이센스 정보를 읽기 때문이였습니다. 해결 방법으로는 클라이언트 PC의 레지스트리에 라이센스 정보를 기록하는 방법이 있지만 요것이 암호화 확인 절차를 거치기 때문에 문제가 있었습니다. 또한 별도의 설치를 필요로 하지 않는다는 스마트 클라이언트 시나리오와도 잘 맞지 않아서, 다른 해결 방법을 찾아야 했습니다.
저의 해결책은 ChartFX의 라이센스 확인 루틴을 가로채서, Entry Assembly 존재 유무에 관계 없이 DLL 내에 기록된 라이센스 정보를 읽도록 하는 것이였습니다. 이렇게 하려면 ChartFX의 내부에 internal 이나 private 로 선언된 클래스와 클래스의 필드를 액세스 해야 했고 이를 위해 이번에도 저의 든든한 후원자 Reflection을 사용했습니다. 그 결과 ChartFX는 멋지게 잘 작동했죠. 이 방법은 일반적인 라이센스 확인루틴을 우회하는 기법은 아니고 오직 ChartFX에만 적용되는 사항이며, 또한 클래스 이름, 메소드 이름, 필드 이름이 맹글링된 결과에 대해 Reflection을 사용했으므로 ChartFX가 새로운 버전(정확히 말하면 DLL에 대해 맹글링을 다시 해버리면)에 대해서는 코딩을 다시 해줘야 한다는 문제가 있습니다. 그래도 작동하니 어딥니까... 그건 그때 가서 생각하기로 하고...
여전히 궁금한 것
지금 프로젝트는 라이센스 확인을 가로채는 삽질로 해결을 했지만, 1년전 S 기업은 왜 ChartFX가 잘되었을까요? 궁금해서 이전 프로젝트 코드(파일럿 코드)를 불러서 Entry Assembly 가 무엇인가 확인해 보았지만 여전히 스마트 클라이언트 시나리오에서는 Entry Assembly가 null 이였습니다. 그렇다면 S 기업에서도 ChartFX는 라이센스 문제가 발생했어야 하는데...
저는 고민을 했습니다... 그때 제 뇌리를 스친건... 혹 ChartFX DLL이 서로 다른 건 아닐까 하는 생각이였죠. S 기업에서 사용했던 ChartFX의 코드를 까 보았습니다. 아니나 다를까... 이 DLL은 Entry Assembly를 확인하는 코드가 없었습니다. ChartFX의 DLL은 닷넷 어셈블리 버전과 파일 버전이 따로 놀고 있었던 겁니다. 즉, S 기업에서 썼던 DLL은 어셈블리 버전이 6.2.1342.0 이였고 파일 버전이 6.2.1539.21391 이였고 이 DLL은 Entry Assembly 유무에 관계 없이 DLL 에서 라이센스 정보를 읽고 있었습니다. 그리고 지금 프로젝트에서 사용하는 ChartFX DLL은 어셈블리 버전이 6.2.1342.0 으로 같았지만 파일 버전이 6.2.1859.20587으로 달랐던 겁니다. 이전 버전에서는 빠져있던 Entry Assembly 확인 루틴이 포함되어 버림으로써 스마트 클라이언트 시나리오에서 ChartFX는 라이센스 문제가 발생되었던 거죠.
교훈
이번 주에도 상당한 삽질과 뷁스런 일을 겪고 얻은 교훈같지 않은... 버전 확인을 확실히 할 것(어셈블리 버전이 같다고 같은 버전은 아니다?) ! 그리고 이번에도 저의 삽질에 많은 도움을 준 Reflector 와 Reflection에게 심심한 감사의 뜻을... -_-
WinForm용 ChartFX를 쓰신다고요? 라이센스 문제가 발생한다고요? EXE 프로젝트의 license.licx에 라이센스 정보를 추가하십시요. 스마트 클라이언트 라구요? 삽을 준비 하십시요... 그리고 저처럼 삽질하십시요... 텨텨텨~~~