항상 ATL ActiveX 만들 때 마다 로직보다는 그냥 사용법 때문에 계속 문서를 찾게 되고 그나마 잘 정리된 문서가 없어서 항상 시간을 많이 보내곤 한다. 그래서 ActiveX를 만들 때 처음에 누구나 하게 되는 작업을 정리해보았다.
1. ATL 컨트롤 생성시 잊지 말고 Support Connection Point 를 체크
Connection Point는 ActiveX가 그 컨테이너에게, 주로 IE, 이벤트를 전달할 수 있게 해준다. ActiveX를 디자인하는데 있어서, 에러 처리나 작업의 완료 등을 알릴 때 이벤트를 이용하면 사용자에게 알리는 부분을 커스터마이징 하기 쉽고, 또한 UI 없이 사용하기도 용이하다. (나중에 손수 만드려면 무척 괴롭다)
다음을 진행하기 전에 먼저 컴파일!!
2. 이벤트 함수 등록
ActiveX의 이벤트가 발생했을 떄 자바 스크립트에서 받을 수 있도록 하기 위해서, 프로젝트의 class view 에서
{프로젝트 이름}Lib 밑에 {_IATL컨트롤이름Events} 라는 dispinterface를 볼 수 있다. 이 인터페이스에 ‘AddMethod’를 눌러 이벤트 함수를 만든다.
그럼 IDL 파일이 바뀐 것을 알 수 있는데, 이 이벤트 함수를 실행하는 코드는 자동 생성되므로 자동 생성을 요청하기 전에 미리 컴파일을 한 번 더 한다.
참고: VS 2008에 ATL 프로젝트 만들때 버그가 무척이나 많다. 컴파일을 안하고 쭉 진행하면 자동 생성이 안된다든지, 파일 내용이 지워진다든지 많은 문제가 있다.
3. 이벤트 호출 함수 생성
class view 에서 자신의 ATL control 에서 우측 버튼을 눌러 add connection point 버튼을 누른다. 그러면 새로운 다이얼로그에 조금전에 수정했던 자신의 dispinterface가 나와야 한다.
참고: 만일 여기서 아무것도 나오지 않는다면 생성된 파일을 한 번 더 조사한다. 문제가 없는 것으로 보인다면 프로젝트를 새로 만드는 편이 문제를 해결하려고 하는 것 보다 빠르다. 혹은 이벤트 호출 함수를 직접 생성하거나 하지만 추천하지 않는다.
문제가 없이 나왔다면 Finish를 누르면 CProxy_… 클래스에 Fire_이벤트 함수 의 함수들이 생성된 것을 볼 수 있다.
4. 자바 스크립트
자바 스크립트에서 ActiveX 이벤트를 받는 표준화된 방법은 없다. ActiveX 자체가 표준이 아니기 때문인데, 여러가지 이벤트를 받는 방법은 가운데 가장 많이 사용되고 안정적인 방법은 다음과 같다.
<script language=javascript for="객체ID" event="함수이름(파라미터)"> </script> <object id="객체ID"></object>
5. 이벤트 호출 테스트
적절한 윈도우 메세지를 하나 잡아서 Fire_이벤트함수이름()으로 테스트해보자. 자바 스크립트에서 alert를 해주고 잘 나오나 확인한다.
6. 메소드, 프라퍼티 그리고 PARAM 태그 읽기
메소드와 프라퍼티를 추가하는 것은 상당히 간단하다. Class View의 I{ATL컨트롤이름} 인터페이스에 AddMethod 와 AddProperty 함수를 이용해서 추가한다.
PARAM 태그를 읽는 것은 먼저 프라퍼티를 위에 기술된 것처럼 하나 만든다음, IPersistPropertyBagImpl을 상속한다. 그리고 COM INTERFACE ENTRY도 아래와 같이 추가해준다.
1 2 3 4 5 6 7 8 9 |
class ATL_NO_VTABLE CSnapshotWindow : .... public IPersistPropertyBagImpl<CSnapshotWindow>, .... { BEGIN_COM_MAP(CSnapshotWindow) COM_INTERFACE_ENTRY(IPersistPropertyBag) END_COM_MAP() }; |
다음으로 PROPERTY MAP에 우리가 방금 만든 프라퍼티를 추가한다.
1 2 3 |
BEGIN_PROP_MAP(CSnapshotWindow) PROP_ENTRY_TYPE("PostURL", 1, CLSID_SnapshotWindow, VT_BSTR) END_PROP_MAP() |
이렇게 하면 맨 처음 프라퍼티를 만들 때 생성된 put_XX, get_XX 함수가 태그를 읽으며 호출된다. 이 getter와 setter를 구현하는 방법은 아래와 같이 하면 편리하다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
CComBSTR m_posturl; // header file에 넣기 STDMETHODIMP CSnapshotWindow::get_PostURL(BSTR* pVal) { *pVal = m_posturl.Copy(); return S_OK; } STDMETHODIMP CSnapshotWindow::put_PostURL(BSTR newVal) { m_posturl = newVal; return S_OK; } |
이것으로 기나긴 PARAM 태그 읽기가 끝났다. 이것은 왜 간단하게 다이얼로그 하나로 구현해주지 않는 지는 알 수 없지만, MSDN 뒤지고, 웹 문서 뒤지는 스킬을 올리기엔 좋은 주제다. (잘 정리된 자료가 없다ㅎ)
7. 스크립트에 안전한 ActiveX 만들기
다음의 클래스를 상속하게 한다.
1 2 3 |
public IObjectSafetyImpl<CSnapshotWindow, INTERFACESAFE_FOR_UNTRUSTED_CALLER | INTERFACESAFE_FOR_UNTRUSTED_DATA>, |
8. 설정 초기화
ActiveX가 여러 프라퍼티를 받아 설정을 초기화하는 시점은 WM_INITDIALOG나 이와 유사한 메시지를 잡아서 처리한다. 그 이유는 WM_INITDIALOG 는 putter들이 모두 호출된 후에 호출되는 것으로 보이기 때문인데, 내게는 항상 이렇게 작동하는지 확신할 수 없다는 것이 문제다. 적어도 param 태그에 대해서는 보장이 되는 것 같다.
따라서 초기화를 하는 가장 마음이 편안한 방법은 PARAM 태그로 초기화 파일을 받는 거다. XML로 받거나 INI의 URL을 받아서 한방에 초기화한다.