학습자료(~2017)/C,C++

Icon Overlay 아이콘 오버레이

단세포소년 2011. 11. 8. 14:53
반응형

이 강좌는 코드 프로젝트에 있는 lallous의 강좌에 기초합니다.

http://www.codeproject.com/shell/overlayicon.asp


간단한 구현을 통해 위와 같이 자신이 만든 아이콘을 원래 아이콘에 덧붙일 수 있습니다.

아이콘 오버레이 라고 하는데요 세 단계를 통해 구현합니다.

1. 아이콘과 함께 기본 COM 객체 구현

2. IShellIconOverlayIdentifier 인터페이스 구현

3. 인터페이스 registering

VS 2005를 이용해 보겠구요.. COM에 대한 얘기는 생략합니다.

COM에 대한 강의는 이 게시판의 박성규 님의 강의를 참고하시면 좋습니다.

 

단계를 설명하기 전에 원리를 설명하도록 하겠습니다.

윈도우의 탐색기는 단순한 어플리케이션이 아닙니다. (빌게이츠가 학창시절 싫어했다던 Tom을 말한단 소리도 있죠....탐새끼...)

윈도우 쉘을 보여주고 구동하는 어플리케이션으로써 작업관리자에 explorer.exe로 나옵니다.

이 프로세스를 종료하면 바탕화면도 작업표시줄도 다 없어집니다. 그럼 다름 프로그램을 시작할 방법이 없어진답니다.

쉘에는 탐색기, 작업표시줄, 바탕 화면 등으로 구성되어 있다고 합니다.

쉘은 윈도우 구동시에 올라오는데 이 쉘에 영향을 주는 프로그램을 쉘 프로그램이라고 합니다.

아이콘 오버레이도 이 기술에 속합니다. 그 중에서도 쉘 익스텐션이라고 하죠.

쉘 익스텐션을 통해 마우스 오른쪽버튼 누르면 나타나는 등록정보창, 아이콘, 트레이 아이콘 등의 조작을 할 수 있습니다.

윈도우 시작과 함께 쉘이 올라올 때 특정 위치의 레지스트리에 등록된 dll(COM 서버)를 로드합니다.

COM 서버에서 어떤 인터페이스를 구현하느냐에 따라 기능이 결정됩니다.

우리는 아이콘 오버레이를 지원하는 인터페이스를 구현할 것입니다.

쉘 프로그래밍은 Dino Esposito의 Professional Visual C++ Windows Shell Programming을 공부해보시면 좋습니다....만

절판이랍니다. -_- 단 이 책에도 아이콘 오버레이에 대한 내용은 없습니다.

그럼 시작하죠.

1 단계

- 프로젝트 생성 시 ATL Project를 선택합니다.

- 프로젝트 이름은 IconOveray라고 하겠습니다.

- Application Settings에서 Dynamic-Link Library(dll) 을 선택합니다. (default입니다)

- MFC를 지원하고 싶으시면 MFC support를 선택합니다.

- 아이콘 리소스를 추가합니다. 그냥 그려서 추가하시면 됩니다.

2 단계

- 클래스 뷰에서 IconOverlay를 마우스 오른쪽버튼 클릭한 후 Add->Class 를 선택합니다

- ATL->ATL Simple Object를 선택하고 Add버튼을 누른 후에 Short Name 에 MyIconOverlay를 적습니다.

- Option은 그대로 두시고 finish 버튼 누릅니다.

- 생성된 클래스는 ShellIconOverlayIdentifiers를 상속해야 합니다.

// MyIconOverlay.h : Declaration of the CMyIconOverlay

#pragma once

#include "resource.h" // main symbols

#include "IconOverlay.h"

#if defined(_WIN32_WCE) && !defined(_CE_DCOM) && !defined(_CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA)

#error "Sin.........atforms."

#endif

#include <shlobj.h>

#include <comdef.h>

// CMyIconOverlay

class ATL_NO_VTABLE CMyIconOverlay :

public CComObjectRootEx<CComSingleThreadModel>,

public CComCoClass<CMyIconOverlay, &CLSID_MyIconOverlay>,

public IDispatchImpl<IMyIconOverlay, &IID_IMyIconOverlay, &LIBID_IconOverlayLib, /*wMajor =*/ 1, /*wMinor =*/ 0>,

public IShellIconOverlayIdentifier

{

public:

CMyIconOverlay()

{

}

// IShellIconOverlayIdentifier 메소드

STDMETHOD(GetOverlayInfo)(LPWSTR pwszIconFile,

int cchMax,int *pIndex,DWORD* pdwFlags);

STDMETHOD(GetPriority)(int* pPriority);

STDMETHOD(IsMemberOf)(LPCWSTR pwszPath,DWORD dwAttrib);

DECLARE_REGISTRY_RESOURCEID(IDR_MYICONOVERLAY)

BEGIN_COM_MAP(CMyIconOverlay)

COM_INTERFACE_ENTRY(IMyIconOverlay)

COM_INTERFACE_ENTRY(IDispatch)

COM_INTERFACE_ENTRY(IShellIconOverlayIdentifier)

END_COM_MAP()

DECLARE_PROTECT_FINAL_CONSTRUCT()

HRESULT FinalConstruct()

{

return S_OK;

}

void FinalRelease()

{

}

public:

};

OBJECT_ENTRY_AUTO(__uuidof(MyIconOverlay), CMyIconOverlay)

- IShellIconOverlayIdentifier의 메소드는 세 개입니다.

◎ GetOverlayInfo 에서는 모듈의 아이콘을 직접 등록합니다.

◎ GetPriority는 아이콘 오버레이가 나타날 순서를 정합니다. 오버레이가 두개 이상 적용될 시 쓰일 거 같습니다.

◎ IsMemberOf 는 파일마다 오버레이가 적용될지 여부를 결정해 줍니다. 파일 이름이나 속성 등으로 결정할 수 있습니다.

예제를 보겠습니다.

// MyIconOverlay.cpp : Implementation of CMyIconOverlay

#include "stdafx.h"

#include "MyIconOverlay.h"

// CMyIconOverlay

// IShellIconOverlayIdentifier::GetOverlayInfo

STDMETHODIMP CCOverlayProvider::GetOverlayInfo(

LPWSTR pwszIconFile,

int cchMax,

int* pIndex,

DWORD* pdwFlags)

{

// 모듈의 위치를 얻어옴

GetModuleFileNameW(_AtlBaseModule.GetModuleInstance(), pwszIconFile, cchMax);

// 리소스에서의 인덱스 설정, 아이콘이 여러개 등록되어 있을 경우 인덱스로 구분함

*pIndex=0;

*pdwFlags = ISIOI_ICONFILE | ISIOI_ICONINDEX;

return S_OK;

}

// IShellIconOverlayIdentifier::GetPriority

STDMETHODIMP CCOverlayProvider::GetPriority(int* pPriority)

{

// 0부터 priority를 설정함

*pPriority=0;

return S_OK;

}

// IShellIconOverlayIdentifier::IsMemberOf

STDMETHODIMP CCOverlayProvider::IsMemberOf(LPCWSTR pwszPath, DWORD dwAttrib)

{

// 유니코드를 LPCSTR로 변환

USE_CONVERSION;

LPCSTR pszPath = W2CA(pwsPath);

/*

파일 경로 : pwszPath (유니코드), pszPath (LPCSTR)

파일 경로를 이용해 파일 이름의 특징이나, 속성등을 알아낸 후에 오버레이 여부 결정

오버레이 : S_OK 반환

그냥 그대로 : S_FALSE; 반환

*/

//doc 파일일 경우 S_OK 반환

if ( strstr(pszPath, ".doc") != 0 )

return S_OK;

else

return S_FALSE;

}

- 간단하죠? 이제 레지스트리에 잘 등록되도록 해주면 됩니다.

단계 3

- IconOverlay.rgs 파일을 엽니다.

- 레지스터 등록하는 코드가 있습니다. 아래에 다음과 같은 코드를 추가하여 줍니다.

//IconOverlay.rgs

HKCR

{

NoRemove AppID

{

'%APPID%' = s 'IconOverlay'

'IconOverlay.DLL'

{

val AppID = s '%APPID%'

}

}

}

//아래에 추가

HKLM

{

NoRemove SOFTWARE

{

NoRemove Microsoft

{

NoRemove Windows

{

NoRemove CurrentVersion

{

NoRemove Explorer

{

NoRemove ShellIconOverlayIdentifiers

{

ForceRemove MyOverlayIcon = s '%APPID%'

{

}

}

}

}

}

}

}

}

- VS 2005에서는 APPID를 변수화 하여서 위와 같이 씁니다만.. VS 6.0 버전에서는 위의 코드에 나와있는 GUID를 복사해서 넣어줘야 합니다.

ex ) ForceRemove MyOverlayIcon = s '{81539FE6-33C7-4CE7-90C7-1C7B8F2F2D40}' //이런 식으로요

자 이제 3단계까지 하셨다면, 컴파일 하여 dll을 등록할 수 있습니다.

컴파일만 해도 등록이 되며, Debug폴더 등에 dll 파일이 생성된걸 확인하실 수 있습니다.

그런데 오버레이가 되지 않는다구요?

당연하죠~ 윈도우 쉘은 이미 실행 되어있고 이 dll은 쉘이 실행될 때 같이 로드됩니다.

로그오프 하신 후 다시 켜시면 오버레이된 아이콘을 볼 수 있습니다.

그러나....

이제부터가 중요합니다.

쉘이 실행될 때만 로드된다면...

한번 코딩해서 확인해 보려면 컴터를 껐다켜고 껐다켜고 해야 한다는 말씀이십니까...

그럼 디버그는 불가능하다는 말씀이십니까...

사실 한번에 완벽한 소스를 만들 수 없기 때문에 디버그는 무쟈게 중요한 문제이지요..

디버그 방법도 알려드립니다.

쉘은 작업관리자에 explorer.exe 로 띄워져 있습니다. 이걸 죽였다가 살리면 그때 로드되겠지요?

근데 죽였다가는 수동으로 살릴 방법이 없습니다. 명령창조차 뜨지 않습니다.

죽이는 건 간단합니다. 작업관리자에서 죽이면 되죠..

살릴 방법은 VS에 있습니다. Project->IconOverlay Property를 누르면 속성창이 뜨지요.. (VS 6.0에서는 Setting으로 나오지요?)

그 곳에 Configuration Property->Debugging에 있는 Command 위치에

C:\WINDOWS\explorer.exe

를 넣어줍니다. 그러면 디버그 모드에서 쉘이 실행되지요...

결론은 이렇습니다.

VS를 띄우고 작업관리자에서 explorer.exe 를 죽인 후 F5로 실행시키면 쉘이 올라옴과 동시에 디버그 모드로 들어가게 됩니다.

이때 디버깅 하십시오.

직접 해보시면 한번 레지스트 된 dll이 다시 써지지 않아 에러가 납니다. 어쩔 수 없이 컴터를 껐다켰다 해야 하는 상황은 발생합니다.

하지만 이렇게 하면 디버깅도 할 수 있고 리붓 횟수도 훨씬 줄일 수 있습니다.

아 그리고 한번 레지스트 된 이후에는 반드시 'regsvr32 /u dll경로명' 을 이용해서 해제 시켜주시는 것도 잊지 마시구요.



출처 : http://www.devpia.com/MAEUL/Contents/Detail.aspx?BoardID=51&MAEULNO=20&no=7397
반응형