ATL ActiveX 만들기 - Part2. 컨트롤 구현
요즘은 확실히 ActiveX 사용이 눈에 띄게 줄어들긴 했지만, 아직도 정신 못차리고(-_-) ActiveX를 요구하는 사람들도 가끔 있다. 아마 앞으로도 한동안은 ActiveX가 필요한 경우가 간혹 있을지도 모르니까, 방법을 다 잊어버리기 전에 요점만 정리해 두자.
초기 작업
ATL 컨트롤을 추가한 다음 프로젝트를 다시 로드해 보면 여러가지 클래스들이 자동으로 구현됨을 확인할 수 있다.
빌어먹을 COM 사양 구현을 일일이 손으로 안해도 되게 해준 Visual Studio 만세! 를 한번 외쳐주자.
이제, 필요하지만 자동으로는 추가되지 않는 항목들을 손으로 추가해 보자.
1. CString
예전에는, 순수 ATL프로젝트를 사용했을 때 가장 큰 문제중에 하나는 CString을 사용할 수 없다는 거였다.
단순히 CString만을 사용하기 위해서 MFC지원 컨트롤을 만드는 경우도 있었다. 그만큼 CString이 편리하기도 하고 CComBSTR과 BSTR만으로 문자열을 조작한다는 것이 지랄맞게 힘들기 때문이다.
그러나!! VS2005부터는 CString이 더이상 MFC만의 것이 아니다! 템플릿 기반으로 작성된 새로운 CString이 도입되었다. 이걸 사용하기 위해서는 stdafx.h에 <atlstr.h>해더파일을 추가해 주면 된다.
- #include <atlstr.h>
어플리케이션 전역에서 사용하기 위해 stdafx.h에다가 삽입한다.
2. Safe For Scripting
이상태에서 ActiveX를 그냥 동작시키면, "스크립트에 안전하지 않다"거나, "초기화 하겠냐" 등의 경고메시지가 출력된다. (Vista 이상에서 나오는 ActiveX를 실행 하겠냐는 경고가 아니다!)
이 문제를 해결하려면, 이 컨트롤은 스크립팅과 초기화에 안전하다는 사실을 컨테이너에게 알려줘야 한다. 여러가지 방법중에 가장 편한 건, 다음 매크로를 HelloCtrl.h에 추가해 주는 방법이다.
- BEGIN_CATEGORY_MAP(CHelloCtrl)
- IMPLEMENTED_CATEGORY (CATID_SafeForScripting)
- IMPLEMENTED_CATEGORY (CATID_SafeForInitializing)
- END_CATEGORY_MAP()
짐작할 수 있듯이, 스크립팅과 초기화에 안전하다는 표시다.
이 외에도 Category map에 추가로 넣을 수 있는 옵션이 몇가지 더 있지만 일반적으로는 사용되지 않는다.
디버거 설정 및 실행
이 상태에서 디버거(F5)를 실행해 보면, "결과물이 EXE가 아니라서 실행할 수 없다. 블라블라~" 하는 오류를 볼 수 있다.
일반적인 디버거로는 ActiveX를 테스트해 볼 수 없으므로, 웹 브라우저 디버거를 사용하자. (물론 IE만 가능하다)
솔루션 탐색기에서 프로젝트를 오른쪽 클릭하고 속성(Property)을 선택한다. Configuration Properties - Debugging에서 Debugger로 Web Browser Debugger를 선택해 준다.
디버거가 실행되면서 컨트롤을 불러올 수 있도록, 시작 URL은 $(ProjectDir)HelloCtrl.htm을 입력해 준다. $(ProjectDir)는 프로젝트 파일이 저장되어있는 로컬 경로를 의미하며, 이곳에는 만들려고 하는 컨트롤의 OBJECT태그가 포함된 컨트롤이름.htm파일이 자동으로 생성되어 있다.
이제 F5를 통해 실행해 보면, 웹 브라우저에서 HelloCtrl.htm이 불려지고, 컨트롤의 모습을 확인할 수 있게된다.
속성(Property) 추가
컨트롤에 속성을 추가해 보자. 이 예제가 Hello World인 만큼, 화면에 출력할 내용으로 Message라는 문자열형 속성을 추가해 보겠다.
클래스 뷰에서 IHelloCtrl을 오른쪽 클릭하고, Add - Add Property를 선택한다.
속성추가 마법사가 표시되면, 문자열형 속성 이므로 BSTR을 선택하고 속성 이름으로 Message를 입력하자.
특별한 경우가 아니라면, IDL속성 설정은 기본값을 그대로 사용하면 된다.
이 과정을 거치면, IDL에는 Message속성이 추가되고, 이 속성의 실제 구현이 CHelloCtrl에 자동으로 추가된다.
속성에 값을 설정하기 위한 put_Message(BSTR newVal)과 속성값을 읽기 위한 get_Message(BSTR* pVal)이 그것이다.
간단하게, 내부의 m_strMessage변수에 값을 읽고 쓰는 정도의 처리만 구현해 보자.
우선 HelloCtrl.h에 멤버변수를 추가한다.
- private:
- CString m_strMessage;
다음은 HelloCtrl.cpp에 속성 구현부를 추가한다.
단순히 m_strMessage를 이용해 값을 읽고 쓰기만 하는 정도로 구현해 보자.
- STDMETHODIMP CHelloCtrl::get_Message(BSTR* pVal)
- {
- m_strMessage.SetSysString(pVal);
- return S_OK;
- }
- STDMETHODIMP CHelloCtrl::put_Message(BSTR newVal)
- {
- m_strMessage = newVal;
- return S_OK;
- }
여기까지 했다면, 이제 속성값을 읽고 쓰여 지는지를 테스트 해 보자.
HelloCtrl.htm에 버튼을 하나 추가하고, 버튼이 클릭되면 Message에 값을 설정한 다음, 스크립트 경고창(alert)으로 그 내용을 보여주는 간단한 스크립트를 추가해 보자.
- <script type="text/javascript">
- function setAndShowMessage() {
- var ctrl = document.getElementById("HelloCtrl");
- ctrl.Message = "Hello GreenB!";
- alert(ctrl.Message);
- }
- </script>
- <object id="HelloCtrl" classid="CLSID:4C80B2EE-6D19-4F77-9946-DF7AD17EEE67"></object>
- <input type="button" onclick="setAndShowMessage()" value="Set Message" />
실행하면, 예상된 결과를 볼 수 있다.
Method 추가
마땅한 기능의 Method가 생각나지 않으니까, 단순하게 Message속성으로 지정된 값을 Windows Message box로 표시해 주는 ShowMessage()라는 쓸데없는-_- 함수를 만들어 보겠다. 이 함수는 사용자가 Message box에서 "예"를 클릭하면 TRUE를, "아니오"를 클릭하면 FALSE를 반환하도록 구성되어 있다.
클래스 뷰에서 IHelloCtrl을 오른쪽 클릭하고, Add - Add Method를 선택한다.
Method 추가 대화상자에서, Method이름과 매개변수를 추가해 준다.
주의할 것은, 모든 COM Method의 반환형은 HRESULT라야 한다. 이는 사용자 논리 단위에서 사용되는 것이 아니라, COM을 호스트와 클라이언트 간의 규약이다. 사용자 논리 레벨에서의 반환값을 사용하고 싶다면, retval로 지정된 포인터형 매개변수를 사용해야 한다.
여기서는, Message box의 제목을 위한 BSTR형의 bstrCaption 매개변수와, 반환값으로 사용될 VARIANT_BOOL*형의 lpvbResult를 추가했다.
CHelloCtrl에 자동으로 추가된 ShowMessage(BSTR bstrCaption, VARIANT_BOOL* lpvbResult)함수에 다음 코드를 추가하자. 실제 구현은 단순하지만, lpvbResult를 통해 어떻게 외부에 값을 반환하는지를 주의깊게 보시기 바란다.
- STDMETHODIMP CHelloCtrl::ShowMessage(BSTR bstrCaption, VARIANT_BOOL* lpvbResult)
- {
- int nMessageBoxResult =
- ::MessageBox
- (
- GetActiveWindow(),
- m_strMessage, bstrCaption,
- MB_YESNO | MB_ICONINFORMATION
- );
- if ( nMessageBoxResult == IDYES )
- *lpvbResult = TRUE;
- else
- *lpvbResult = FALSE;
- return S_OK;
- }
Method의 동작을 확인하기 위해 스크립트 코드를 HelloCtrl.htm에 추가하자.
- <script type="text/javascript">
- ...
- function callShowMessage() {
- var ctrl = document.getElementById("HelloCtrl");
- ctrl.Message = "Hello GreenB!";
- if (ctrl.ShowMessage("GreenmaruX") == true) {
- alert("Yes button clicked.");
- }
- else {
- alert("No button clicked.");
- }
- }
- </script>
- </head>
- <body>
- ...
- <input type="button" onclick="callShowMessage()" value="Call ShowMessage" />
- ...
실행시켜 보면, 컨트롤과 익스플로러에서 각각 한번씩 Message box를 표시될 것이다.
소스코드 다운로드
예제 프로젝트 파일(Visual Studio 2010)
다음 글에서는, Connection point를 구현하여 컨트롤에 이벤트를 추가해 보도록 하겠다.
'소프트웨어 개발' 카테고리의 다른 글
| ATL ActiveX 만들기 - Part4. 관리자권한 UAC Elevation (17) | 2010/07/29 |
|---|---|
| ATL ActiveX 만들기 - Part3. 이벤트(Connection point) 구현 (8) | 2010/07/05 |
| ATL ActiveX 만들기 - Part2. 컨트롤 구현 (10) | 2010/06/23 |
| ATL ActiveX 만들기 - Part1. 프로젝트 구성 (12) | 2010/06/22 |
| RGB를 Int32로 변환하기 (8) | 2009/10/13 |
| enum에 여러 상태를 포함시키기 (20) | 2009/10/07 |

GreenmaruX_Part2.zip
Tag //

Comment List
음..저는 실력은 없지만 보안에 조금 관심이 있어서 국내 및 해외의 유명 백신업체들의 공식홈페이지 등에서 최신 악성코드 등에 대한 정보를 얻고 있는데..국내 및 해외의 유명 백신업체들이 웹브라우저를 이용한 온라인 악성코드 검사 서비스를 액티브X로 제공하고 있더군요. 그러고보면 액티브X도 잘만 활용한다면 나쁜점만 있는건 아닌것 같다는 생각이 듭니다. 가장 큰 문제는 액티브X를 악용하는 쓰레기 업체겠지만요.
뭐든 다 그렇죠 ㅎㅎ 예리한 칼은 누가 어떻게 쓰느냐가 문제인거죠.
뭔소리냐..
재밌는 글이나 좀 올려라 ㅡ.ㅡ;
재미있구만! 찬찬히 보다보면 염통이 쫄깃해 지실꺼임 ㅋ
깔끔하니 정리 잘 해두셨네요~
잘보고 갑니다!! ^^
무지 힘든 내용을(머리에 쥐나는 내용을)
이리도 쉽고 깔끔하게 정리하시다니 정말로 감사히 잘 봤습니다.^^
htm 파일 자동생성하려면 초기설정을 해줘야하남요? ㅠ
htm 파일은 컨트롤 형식으로 개체 만들면 자동으로 생겨요
콩 심은데 콩나고, 팥 심은데 팥난다.
원숭이도 나무에서 떨어진다.