- 옵션에서 Support MFC를 체크 하도록 한다.
2. ATL Control 추가 (필자는 ApBroker로 생성)
- 옵션은 걍 다음 다음으로 넘겨버렸다. -ㅁ-;
3. 레지스트리 수정
ApBroker.rgs 파일 수정
HKCR
{
ApLauncher.ApBroker.1 = s 'ApBroker Class'
{
CLSID = s '{FC9E01FE-A5E6-43FD-A925-9D5F6803E779}'
}
ApLauncher.ApBroker = s 'ApBroker Class'
{
CLSID = s '{FC9E01FE-A5E6-43FD-A925-9D5F6803E779}'
CurVer = s 'ApLauncher.ApBroker.1'
}
NoRemove CLSID
{
ForceRemove {FC9E01FE-A5E6-43FD-A925-9D5F6803E779} = s 'ApBroker Class'
{
ProgID = s 'ApLauncher.ApBroker.1'
VersionIndependentProgID = s 'ApLauncher.ApBroker'
ForceRemove 'Programmable'
InprocServer32 = s '%MODULE%'
{
val ThreadingModel = s 'Apartment'
}
val AppID = s '%APPID%'
Elevation
{
val Enabled = d 1
}
val LocalizedString = s '@%MODULE%,-101'
ForceRemove 'Control'
ForceRemove 'ToolboxBitmap32' = s '%MODULE%, 103'
'MiscStatus' = s '0'
{
'1' = s '%OLEMISC%'
}
'TypeLib' = s '{B0EA13FC-8B95-4C3E-9627-D8937BFEDBCD}'
'Version' = s '1.0'
}
}
}
주의 : String Table에 101번에 대한 String 추가할 것
빨간색으로 된 부분이 추가 되어야 하는 부분이다. 이 때 101번 String은 권한 상승시에 사용된다. (각자 확인 해보세요~)
ApLauncher.rgs 수정
HKCR
{
NoRemove AppID
{
'%APPID%' = s 'ApLauncher'
{
val DllSurrogate = s ''
}
'ApLauncher.DLL'
{
val AppID = s '%APPID%'
}
}
4. Broker 함수 추가
이제 권한 상승 함수와 실제 다이얼로그를 띄우는 부분을 추가해야 겠다.
프로젝스 프로퍼티창에서
- IApBroker – Add – Add Method - RunBroker 함수 추가
- IApBroker – Add – Add Method - RunProgram 함수 추가
- IsVistaOS 함수와 CoCreateInstanceAsAdmin 함수 추가(어디든 CApBroker 클래스가 참조할 수 있으면 됩니다.
클래스 함수로 포함시키면 좋겠지요...
isVistaOS 함수 착성
{
BOOL bIsVista = FALSE;
OSVERSIONINFO sInfo;
sInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
//
// OS VERSION CHECK.
//
if(::GetVersionEx(&sInfo)) {
if( sInfo.dwPlatformId == VER_PLATFORM_WIN32_NT &&
sInfo.dwMajorVersion >= 6 &&
sInfo.dwMinorVersion >= 0) { // Windows VISTA
bIsVista = TRUE;
}
}
CoCreateInstanceAsAdmin 함수 작성
{
BIND_OPTS3 bo;
WCHAR wszCLSID[50];
WCHAR wszMonikerName[300];
StringFromGUID2(rclsid, wszCLSID, sizeof(wszCLSID)/sizeof(wszCLSID[0]));
HRESULT hr = S_OK ;
if( bAdministrator)
hr = StringCchPrintfW(wszMonikerName, sizeof(wszMonikerName)/sizeof(wszMonikerName[0]), L"Elevation:Administrator!new:%s", wszCLSID);
else
hr = StringCchPrintfW(wszMonikerName, sizeof(wszMonikerName)/sizeof(wszMonikerName[0]), L"Elevation:HighestAvailable!new:%s", wszCLSID);
if (FAILED(hr))
return hr;
memset(&bo, 0, sizeof(bo));
bo.cbStruct = sizeof(bo);
bo.hwnd = hwnd;
bo.dwClassContext = CLSCTX_LOCAL_SERVER;
return CoGetObject(wszMonikerName, &bo, riid, ppv);
}
RunBroker 함수 작성
STDMETHODIMP CApBroker::RunBroker(void)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
HRESULT hr;
HWND hwnd = NULL;
IApBroker* objElevator = NULL;
const GUID guidCurrentObject = CLSID_ApBroker;
const IID iidCurrentObject = IID_IApBroker;
CoInitialize(NULL);
if(!IsVistaOS()) {
//
// VISTA 가아닌경우.
//
RunProgram();
return S_OK;
}
//
// 권한상승(ELEVATION)
//
hr = CoCreateInstanceAsAdmin(NULL, guidCurrentObject, iidCurrentObject, (void**)(&objElevator), TRUE);
//
// EXECUTE
//
if(SUCCEEDED(hr)) {
// do work.
objElevator->RunProgram();
// release.
objElevator->Release();
return S_OK;
} else {
//
// Elevation 실패.
//
CString sErr;
sErr.Format(_T("CoCreateInstanceAsAdmin failed! HResult: %x"), hr);
::MessageBox(NULL, sErr, _T("ApBroker") , MB_OK);
}
return S_OK;
}
실행하고 있습니다. 이부분을 유의해서 보시면 됩니다.
RunProgram 함수 작성
STDMETHODIMP CApBroker::RunProgram(void)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
// TODO: Add your implementation code here
CDlgMain m_DlgMain;
m_DlgMain.DoModal();
return S_OK;
}
자 지금까진 공통적인 부분이었고 저기 CDlgMain m_DlGmain; 부분을 봅시다.
필자는 다이얼로그를 하나 추가해서 연결해 두었습니다.
그리고 CApBroker::RunProgram 안에서 호출하고 있습니다.
따라서 기존 MFC 프로그래밍 하는 것처럼 코딩하시고 권한 상승 부분만 ATL을 이용합니다.
필자는 ATL을 해본적도 없고 MFC를 좀 하던차에 ActiveX를 만들어야 했기 때문에
좀 편하게 코딩해보가 이런 꼼수를 사용했습니다.
(더 확실한 것은 아예 모두 MFC로 만드는 것이겠지요. 필자는 하다하다 포기했습니다.
방법을 아시는 분은 링크좀.. ㅡㅡ;)
5. 안정성 코드 추가
안정성 코드는 이 엑티브 엑스를 정말로 실행해도 됩니까? 하는 것을 빼게 해줍니다.
그냥 빨간 부분 추가만 해주시면 됩니다.
ApLauncher.cpp 수정
- CreateComponentCategory 함수 추가
- RegisterCLSIDInCategory 함수 추가
{
ICatRegister* pcr = NULL ; // interface pointer
HRESULT hr = S_OK ;
hr = CoCreateInstance(CLSID_StdComponentCategoriesMgr,
NULL, CLSCTX_INPROC_SERVER, IID_ICatRegister, (void**)&pcr);
if (FAILED(hr)) {
return hr;
}
// Make sure the HKCR\Component Categories\{..catid...}
// key is registered
CATEGORYINFO catinfo;
catinfo.catid = catid;
catinfo.lcid = 0x0409 ; // english
// Make sure the provided description is not too long.
// Only copy the first 127 characters if it is
int len = (int)wcslen(catDescription);
if (len>127)
len = 127;
wcsncpy_s(catinfo.szDescription, catDescription, len);
// Make sure the description is null terminated
catinfo.szDescription[len] = '\0';
hr = pcr->RegisterCategories(1, &catinfo);
pcr->Release();
return hr;
}
HRESULT RegisterCLSIDInCategory(REFCLSID clsid, CATID catid)
{
// Register your component categories information.
ICatRegister* pcr = NULL ;
HRESULT hr = S_OK ;
hr = CoCreateInstance(CLSID_StdComponentCategoriesMgr,
NULL, CLSCTX_INPROC_SERVER, IID_ICatRegister, (void**)&pcr);
if (SUCCEEDED(hr))
{
// Register this category as being "implemented" by
// the class.
CATID rgcatid[1] ;
rgcatid[0] = catid;
hr = pcr->RegisterClassImplCategories(clsid, 1, rgcatid);
}
if (pcr != NULL)
pcr->Release();
return hr;
}
빨간 부분 추가
STDAPI DllRegisterServer(void)
{
// registers object, typelib and all interfaces in typelib
HRESULT hr = _AtlModule.DllRegisterServer();
#ifdef _MERGE_PROXYSTUB
if (FAILED(hr))
return hr;
hr = PrxDllRegisterServer();
#endif
/////////////////////////////////////////////////////////////////////////////
// 안전성코드추가SAFE FOR SCRIPTING.
/////////////////////////////////////////////////////////////////////////////
const CATID CATID_SafeForScripting =
{ 0x7dd95801, 0x9882, 0x11cf, { 0x9f, 0xa9, 0x00, 0xaa, 0x00, 0x6c, 0x42, 0xc4 } };
const CATID CATID_SafeForInitializing =
{ 0x7dd95802, 0x9882, 0x11cf, { 0x9f, 0xa9, 0x00, 0xaa, 0x00, 0x6c, 0x42, 0xc4 } };
REFCLSID clsidCurrentActiveX = CLSID_ApBroker;
CoInitialize( NULL );
if (FAILED( CreateComponentCategory(CATID_SafeForScripting, L"Controls that are safely scriptable") )) {
return ResultFromScode(SELFREG_E_CLASS);
}
if (FAILED( CreateComponentCategory(CATID_SafeForInitializing, L"Controls safely initializable from persistent data") )) {
return ResultFromScode(SELFREG_E_CLASS);
}
if (FAILED( RegisterCLSIDInCategory(clsidCurrentActiveX, CATID_SafeForScripting) )) {
return ResultFromScode(SELFREG_E_CLASS);
}
if (FAILED( RegisterCLSIDInCategory(clsidCurrentActiveX, CATID_SafeForInitializing) )) {
return ResultFromScode(SELFREG_E_CLASS);
}
return hr;
================================================================
에고에고 힘들다. 있는거 가져다 붙이는 것도 힘드네요.
다시 말씀드리자면 이 방법은 MFC 이용하여 권한 상승을 하지는 않습니다.
정확히는 ATL 기반에서 권한 상승하고 MFC를 쓰는 것이지요.
포스팅이 너무 늦어버렸네요..
'ActiveX' 카테고리의 다른 글
ATL - ActiveX 제작 강의 - 박성규 (3) | 2008.07.29 |
---|---|
카테고리 : ATL/ActiveX 정리 사이트 링크 (0) | 2008.07.29 |
ATL을 이용한 다이얼로그 기반의 ActiveX 만들어 놓은 소스입니다. (1) | 2008.07.29 |
ATL ActiveX Control 만들기 - 예제2 (0) | 2008.07.29 |
ATL을 이용하여 ActiveX 컨트롤 만들기 (1) | 2008.07.29 |
MFC 이용 ActiveX 만들기, html 안전로딩 방법 포함 (0) | 2008.07.29 |
ActiveX 컨트롤에서의 IObjectSafety 인터페이스 구현 (2) | 2008.07.25 |