본문 바로가기
일하는 중에

CS 프로그램의 일부를 ActiveX로 포팅하기-들어가는 말

by likebnb 2013. 12. 4.

To conquer without risk is to triumph without glory.



0. 들어가는 말

최근 두 달 동안 재밌는 일을 맡아서 진행했다. 십여 년 정도의 역사를 갖고 있는 전형적인 MFC 기반의 CS 프로그램을 

ActiveX로 포팅해 달라는 것이었다. 십여 년의 역사라는 것이 의미하는 것은 프로그램이 처음 개발되고 난 이후 줄곧 추가되고 

수정되어 왔으며 강산이 바뀐다는 세월 동안 여러 개발자의 손에 맡겨져서 그 코드가 비대해지고 난잡해졌다는 것이다.


이런 코드를 분석하는 것도 일이지만 개발에 주어진 시간도 반토막 난(먼저 의뢰를 받았던 개발자가 그 반토막의 시간을 끌다가 포기한) 

상황에서 약속 시간을 지킬 수 있을지가 의문이었지만 내가 어려울 때 도움을 받았던 동료 개발자의 부탁도 있고 해서 이 일을 맡기로 했다.


짧은 기간 동안 여러 가지 난제들을 겪었다. 주어진 요구사항으로 인해 피해갈 수 없는 문제들이었기에 반드시 해결해야만 했고 

결국 모든 문제들을 풀었기에 약속한 시간 안에 일을 마칠 수 있었다. 하여 여기에 그 동안 만났던 여러 가지 문제들을 정리하여

기록해 두고자 한다. 


오늘은 그 첫번째 기록으로 각각의 에피소드들에 대한 간단한 소개글을 쓰고자 한다.



1. 어떻게 만들까?

주어진 개발 기간은 한 달, 분석해야 할 원본 소스는 약 60여 개의 개별 project들로 이루어진 MFC 기반의 VC++, 

독자적인 개발 프레임웍이 적용되었다. 메인 윈도는 전형적인 SDI 구조이며 메인 윈도를 제외한 각 화면들은 모두 DLL 형태로 개발되었고, 

이들 중 일부를 ActiveX로 포팅해야 하는 상황이다. 그래서 MFC SDI 기반의 ActiveX를 만들어 기존 메인 윈도를 대신하고

각 화면의 DLL은 그대로 차용해서 쓰는 방법을 택했다. 


하지만 프레임 윈도와는 태생이 다른 ActiveX이기에 예기치 못한 많은 문제들이 곳곳에 복병처럼 숨어서 기다리고 있었으니… 



2. MFC SDI 기반의 ActiveX

첫번째 문제는 MFC SDI 기반의 ActiveX를 만드는 것이다. 일반적으로 인터넷 브라우저 안에 자리를 잡는 ActiveX는 타이틀바도 메뉴바나 

툴바도 없는, 말 그대로 알맹이만 있는 형태로 만든다. 그러니 SDI의 형식은 빌려오되 모양은 밋밋한 다이얼로그(Dialog)가 되어야 한다. 

당연하게 이 다이얼로그는 팝업이 아니라 정해진 제 자리에 착 붙어 있어야 한다. 그리고 HTML에서 기술한 태그 <OBJECT>의 속성인 

WIDTH, HEIGHT의 값을 상속 받아 다이얼로그(View)의 크기가 결정되어야 한다. 시작부터 만만하지 않다.



3. 사용하기에 안전한 코드(프로그램)임을 알려주기

어찌어찌 하여 MFC SDI 기반의 ActiveX는 만들었다. 테스트를 위해 HTML 파일을 만들어서 ActiveX를 끼워넣고 브라우저에서 보려는데 

자꾸 보안 경고창이 뜬다. 귀찮다. 이거 안 뜨게 하는 방법은 없을까?



4. ActiveX에서 다른 DLL 가져다 쓰기

자 이제 메인 윈도를 대신할 SDI ActiveX는 만들었다. 이제 실제로 기능을 수행할 화면을 담고 있는 DLL을 불러오도록 하자. 

프로그램에서 외부의 DLL을 사용하려면 AfxLoadLibrary()함수를 이용해 메모리로 불러들여야 한다. 당연한 얘기지만 사용할 

DLL의 전체경로는 알고 있어야 한다. AfxLoadLibrary()로 DLL을 불러오는 것은 어렵지 않다. 그런데 문제는 이렇게 불러들인 

DLL이 또 다른 DLL들을 사용해야 한다는 것이다. 그리고 이들 DLL들은 경로 없이 이름으로만 참조하고 있어서 필요한 DLL들을 

찾지 못하는 문제가 발생했다.  이를 해결하기 위해 두 가지 방법을 사용했다.



5. DLL에서 함수 export 하기 

이제 필요한 DLL을 메모리에 불러들였고 DLL들 간의 종속성 문제도 해결했다. 이제 DLL 안에 숨어 있는 함수들을 필요할 때 불러다 쓰면 

되는데 어떻게 하면 될까? DLL을 메모리에 불러들이면 그 DLL에 정의된 클래스들과 그 멤버함수들을 곧 바로 쓸 수 있을 줄 알았는데 

컴파일도 되질 않는다. DLL 안에 정의된 함수들을 쓰려면 *.def 파일에서 해당 함수의 이름을 바깥 세상으로 공표해줘야 한다. 

이럴 때 쓰는 말이 바로 export라는 것이다.



6. DLL에서 보내는 윈도 메시지를 ActiveX에서 처리하기

개발 진행 단계가 서서히 중반으로 가고 있다. 그런데 또 다른 난관에 부딪혔다. 인터넷 브라우저에서 F11 키를 눌러 봤는가? 

기존 DLL에서 이 키를 자체 도움말을 활성화하는데 사용하고 있다. 즉 사용자가 F11 키를 누른 것을 감지하여 도움말을 보여주는 함수를 

호출하도록 메시지 전 처리를 하고 있는데 ActiveX는 기본적으로 이런 메시지 전 처리 기능이 없다. 

그렇다고 십 년 넘도록 몸에 밴 F11은 도움말이라는 고정관념을 깨고 이젠 도움말을 보려면 버튼을 클릭하라고 설득할 수는 없는 노릇이다. 

그래서 메시지 후킹 방법을 도입하기로 했다.



7. 사용자 정의 메시지는 어떻게 처리할까?

WM_LBUTTONDOWN 등의 메시지 처리는 잘 된다. 그런데 이 프로그램, 사용자 정의 메시지가 있다. ActiveX에 설치한 메시지 후킹 

핸들러에선 이 사용자 정의 메시지가 잡히질 않는다. 뭐가 문제일까? 윈도는 프로세스와 쓰레드 간 통신을 메시지를 전달하는 방법으로 

구현했다. 보내는 쪽과 받는 쪽이 서로 약속하고 주고 받는 것이다. 이 약속, 즉 프로토콜이 지켜지지 않으면 제 아무리 긴요한 메시지라도 

받는 쪽에선 그 존재조차 알 수 없는 법이다. ActiveX 쪽에서 메시지를 핸들링하려면 정해진 형식대로 메시지를 만들어서 보내야 한다.



8. DLL에서 ActiveX를 통해 자바스크립트 함수 호출하기

이제 이번 개발의 마지막 과제가 남았다. ActiveX에서 DLL을 통해 띄운 모달 다이얼로그에서 사용자가 용무를 마치고 확인 버튼을 

클릭하면 그 내용이 인터넷 브라우저의 특정 객체에 반영되어야 한다. 즉 ActiveX 바깥으로 정보를 보내야 한다는 것이다. 

이를 위해 보통은 JavaScript를 이용한다. 하지만 DLL에서 어떻게 자바스크립트를 호출할 수 있을까? 이 자바스크립트는 ActiveX 

객체를 생성한 HTML에 기술되어 있으며 이 HTML 문서는 인터넷 브라우저에 의해 렌더링 되었고, 렌더링 과정에서 초기화된 

AvtiveX가 DLL을 메모리로 불러들인 것이다. DLL > ActiveX > 인터넷 브라우저 > HTML 문서 > 자바스크립트 함수와 같은

순서로 참조가 되어야 할 것이다. 휴~ 긴 문장이다. 이미 답을 다 말한 것 같다.  



9. 포인터, 양날의 검

모든 문제를 다 넘어왔다고 생각했다. 그런데 프로그램을 만드는 사람과 프로그램을 쓰는 사람은 왜 그렇게 다른지!

애초에 이 프로그램을 설계할 때 하나의 ActiveX를 세 가지 용도로 사용할 수 있게 했다. ActiveX를 초기화 할 때 매개변수를

넘겨서 지정한 화면으로 기동하도록 말이다. 그리고 두 가지 이상 화면이 동시에 기동될 경우는 없을 것이라 단정하였건만

현실은 그렇지 아니하였다. 결국 DLL에서 ActiveX를 통해 자바스크립트 함수를 호출하기 위해 설치했던 OLE컨트롤러의 포인터

전역변수가 문제를 일으킨 것이다. 포인터, 잘 쓰면 기가 막힌 명검이요 잘 못 다루면 가슴에 비수를 꽂는다.





이제 각 에피소드들을 하나씩 만나보도록 하겠습니다.