안녕하세요. 명월입니다.
이번 포스팅에서는 ActiveX 개발에 관한 포스팅입니다. 최근 웹 어플리케이션의 추세는 ActiveX가 점점 죽어가는 현실입니다.
실제로 ActiveX는 보안에도 취약하고 각종 악성코드 등을 양상해 내놓기 때문에 비추천 개발프로젝트 중 하나 입니다.
그러나 그렇게 안 좋은 코드, 프로그램이면서도 한국에서는 많이 사용하는 이유는 웹과 CS(Client Server)프로그램을 연결 시켜주기 때문입니다. 죽 웹폼과 어플리케이션, 어플리케이션과 웹폼과 통신이 된다고 생각하면 됩니다.
즉, 웹의 장점과 CS의 장점을 다 취할 수 있는 코드이기 때문에 아직도 많이 사용되는 것 입니다.
(이 말을 다시 말하면 복잡한 개발 코드가 간단하게 작성이 될 수 있다라는 뜻입니다.)
일단 그건 추세이고, 내가 ActiveX가 안좋다 또는 ActiveX를 비판하게 앞서 ActiveX 가 무엇인지 알아 둘 필요가 있습니다.
새 프로젝트가 생성되면 [프로젝트] -> 속성을 확인 하겠습니다.
속성에서 먼저 MFC사용을 정적으로 바꿉니다.
큰 프로젝트에서는 여러 라이브러리를 연결해서 사용하기 때문에 컴파일 용량을 줄일 수 있습니다.
그러나 이런 작은 프로그램 만들 때는 라이브러리를 연결하는 것이 어렵기 때문에 정적으로 선언을 하는게 용량은 크지만 실행상에 에러를 줄일 수 있습니다.
그외는 문자 집합은 유니코드로 설정합니다. 설정이 완료되면 확인을 누릅니다.
소스파일을 보면 파일이 총 6개 있습니다.
파일명 어미는 프로젝트 이름으로 자동 생성 되었고 그 외 cpp, 컨트럴.cpp, idl 등으로 나뉩니다. 여기서 먼저 수정을 해야 할 것은 cpp 부분입니다.
ActiveX_20120914.cpp를 확인하겠습니다.
윗 부분에 해더를 선언합니다.
#include "comcat.h"
#include "strsafe.h"
#include "objsafe.h"
그런후에 밑에 const CATID CLSID_SafeItem를 수정합니다.
수정하는 방법은 옆에 ActiveX_20120914Ctrl.cpp 파일을 확인하면 IMPLEMENT_OLECREATE_EX 이란 메소드가 있습니다.
거기 밑에 uuid 코드를 가져 옵니다.
4번째부터 끝자리수를 따로 다시 묶습니다.
IMPLEMENT_OLECREATE_EX(CActiveX_20120914Ctrl, "ACTIVEX_20120914.ActiveX_20120914Ctrl.1", 0xf8e13d79, 0x5aa8, 0x40b1, 0xbe, 0x32, 0xfd, 0xef, 0xd1, 0xfb, 0xfe, 0xcc)
// 아래와 같이 바꾼다.
const CATID CLSID_SafeItem ={ 0xf8e13d79, 0x5aa8, 0x40b1, {0xbe, 0x32, 0xfd, 0xef, 0xd1, 0xfb, 0xfe, 0xcc}};
카테고리를 추가합니다.
HRESULT CreateComponentCategory(CATID catid, WCHAR *catDescription)
{
ICatRegister *pcr = NULL ;
HRESULT hr = S_OK ;
hr = CoCreateInstance(CLSID_StdComponentCategoriesMgr,NULL, CLSCTX_INPROC_SERVER, IID_ICatRegister, (void**)&pcr);
if (FAILED(hr)) return hr;
CATEGORYINFO catinfo;
catinfo.catid = catid;
catinfo.lcid = 0x0409;
size_t len;
hr = StringCchLength(catDescription, STRSAFE_MAX_CCH, &len);
if (SUCCEEDED(hr))
{
if (len>127)
{
len = 127;
}
}
else
{
}
hr = StringCchCopy(catinfo.szDescription, len + 1, catDescription);
catinfo.szDescription[len + 1] = '\0';
hr = pcr->RegisterCategories(1, &catinfo);
pcr->Release();
return hr;
}
HRESULT RegisterCLSIDInCategory(REFCLSID clsid, CATID catid)
{
ICatRegister *pcr = NULL ;
HRESULT hr = S_OK ;
hr = CoCreateInstance(CLSID_StdComponentCategoriesMgr,NULL, CLSCTX_INPROC_SERVER, IID_ICatRegister, (void**)&pcr);
if (SUCCEEDED(hr))
{
CATID rgcatid[1] ;
rgcatid[0] = catid;
hr = pcr->RegisterClassImplCategories(clsid, 1, rgcatid);
}
if (pcr != NULL)
{
pcr->Release();
}
return hr;
}
HRESULT UnRegisterCLSIDInCategory(REFCLSID clsid, CATID catid)
{
ICatRegister *pcr = NULL ;
HRESULT hr = S_OK ;
hr = CoCreateInstance(CLSID_StdComponentCategoriesMgr,NULL, CLSCTX_INPROC_SERVER, IID_ICatRegister, (void**)&pcr);
if (SUCCEEDED(hr))
{
CATID rgcatid[1] ;
rgcatid[0] = catid;
hr = pcr->UnRegisterClassImplCategories(clsid, 1, rgcatid);
}
if (pcr != NULL)
{
pcr->Release();
}
return hr;
}
그리고 레지스트리 등록 메소드를 변경합니다.
STDAPI DllRegisterServer(void)
{
HRESULT hr;
AFX_MANAGE_STATE(_afxModuleAddrThis);
if (!AfxOleRegisterTypeLib(AfxGetInstanceHandle(), _tlid))
{
return ResultFromScode(SELFREG_E_TYPELIB);
}
if (!COleObjectFactoryEx::UpdateRegistryAll(TRUE))
{
return ResultFromScode(SELFREG_E_CLASS);
}
hr = CreateComponentCategory(CATID_SafeForInitializing,L"Controls safely initializable from persistent data!");
if (FAILED(hr))
{
return hr;
}
hr = RegisterCLSIDInCategory(CLSID_SafeItem,CATID_SafeForInitializing);
if (FAILED(hr))
{
return hr;
}
hr = CreateComponentCategory(CATID_SafeForScripting,L"Controls safely scriptable!");
if (FAILED(hr))
{
return hr;
}
hr = RegisterCLSIDInCategory(CLSID_SafeItem,CATID_SafeForScripting);
if (FAILED(hr))
{
return hr;
}
return NOERROR;
}
STDAPI DllUnregisterServer(void)
{
HRESULT hr;
AFX_MANAGE_STATE(_afxModuleAddrThis);
if (!AfxOleUnregisterTypeLib(_tlid, _wVerMajor, _wVerMinor))
{
return ResultFromScode(SELFREG_E_TYPELIB);
}
if (!COleObjectFactoryEx::UpdateRegistryAll(FALSE))
{
return ResultFromScode(SELFREG_E_CLASS);
}
hr=UnRegisterCLSIDInCategory(CLSID_SafeItem,CATID_SafeForInitializing);
if (FAILED(hr))
{
return hr;
}
hr=UnRegisterCLSIDInCategory(CLSID_SafeItem,CATID_SafeForScripting);
if (FAILED(hr))
{
return hr;
}
return NOERROR;
}
기본 설정은 완료 되었습니다.
그럼 이제 메소드를 만들어 보겠습니다.
ActiveX20120914Ctrl.cpp 를 들어가서 가장 밑에다가 입력하겠습니다.
void CActiveX_20120914Ctrl::TestFunction(LPCSTR Parameter)
{
AfxMessageBox((LPCTSTR)Parameter);
}
C++에서 메소드 등록을 하려면 헤더를 등록 해야 합니다.
ActiveX20120914Ctrl.h 로 가서 등록하겠습니다.
중간에 public 에 void TestFunction(LPCSTR Parameter); 라고 등록하였습니다.
다시 ActiveX20120914Ctrl.cpp 로 돌아가서 디스패치 맵을 수정합니다
윗부분에 있습니다.
DISP_FUNCTION(CLinkCtrl, "TestFunction", TestFunction, VT_EMPTY, VTS_BSTR)
이제 F6를 눌러서 컴파일을 합니다. (ActiveX는 웹에서 기동을 하기 때문에 디버깅또는 실행이 되지 않습니다.)
Debug 폴더 가보면 OCX 파일이 있습니다.
웹 문서를 작성하겠습니다.
Test 오브젝트를 불러서 그안의 TestFunction 함수를 불러드립니다.
참고로 clsid(클래스 아이디)는 프로젝트의 옆에 ActiveX_20120914.idl 가장 밑에 보면 uuid 가 있습니다. 그게 클래스 아이디 입니다. ( 밑에 사진은 중간에 제가 프로젝트를 지워버린 바람에 다시 만들어서 프로젝트 명이 바뀌었습니다.)
요렇게 맞추고 끝나냐 아닙니다.
그리고 등록하는 단계 시작버튼 -> 실행 -> CMD를 눌러서 해당 디렉토리에 갑니다.
Regsvr32 ActiveX_20120914.ocx 로 등록을 합니다.
그런 후에 웹페이지 만든 것을 같은 폴더에 둡니다. (사실 등록 완료되면 레지스트리 따라서 움직이니 같은 폴더 개념은 의미가 없습니다.)
그리고 실행해봅니다.
ActiveX가 실행 된 화면입니다.
예제 파일입니다.
※ 설명이랑 예제 이미지랑 안 맞을 수 있습니다. 무슨 영문인지 이미지가 싹 지워져 있었네요.ㅜㅜ
일단 다시 스샷을 찍어서 올리기는 했으나 소스는 안틀리나 프로젝트명이라던가 UUID코드가 약간은 다를 수 있습니다.
'Development note > C , C++ , MFC' 카테고리의 다른 글
[C++] C++에서 사용되는 문자열 타입(LPSTR, LPCSTR, LPCTSTR, LPCWSTR), 메모리 누수(memory leak) 체크하는 방법과 UTF8 변환하는 방법 (0) | 2020.04.17 |
---|---|
[C++] C++과 C#의 소켓 통신을 이용해 파일 전송하는 방법 (0) | 2020.04.16 |
[C++] C++과 C#의 소켓 통신을 하는 방법(문자열 송수신) (0) | 2020.04.15 |
[MFC] 서비스 프로그램 (6) | 2012.12.02 |
[C++] ShowWindow 메크로 상수, Window 메시지 상수 (0) | 2012.10.20 |
[C++] afxsock 통신 - 클라이언트편 (0) | 2012.09.30 |
[C++] afxsock 통신 - 서버편 (0) | 2012.09.30 |
[C++] C++ Dll 만들어서 C#에서 사용하기 (마샬링) (2) | 2012.09.23 |