아래는 김기용님이 작성하신 내용입니다.
32비트에서 컴파일할 경우 이상없이 동작하지만 64비트일 경우 아래와 같이 약간 수정해줘야 합니다.
1. 컴파일 구성에서 Win32에서 64비트로 변경
2. 링크->고급->대상컴퓨터 : MachineX64(/MACHINE:X64)로 변경(변경되어 있지 않은 경우만 변경)
3. 일반->ATL 사용 : ATL에 정적 링크
4. C/C++->코드 생성->런타임 라이브러리 : 다중 스레드로 변경(컴파일 및 동작이 이상없으면 적용X)
STDMETHOD(GetCommandString)(UINT, UINT, UINT*, LPSTR, UINT);
->
STDMETHOD(GetCommandString)(UINT_PTR, UINT, UINT*, LPSTR, UINT);
기존 생성된 프로젝트일 경우 위 소스만 변경후 64비트 컴파일 구성을 한 후 SysWOW64폴더에있는 regsvr32.exe파일을 이용하여 등록
신규로 생성한 프로그램은 system32폴더에 있는 regsvr32.exe로 등록
출처:http://devroid.com/80105559342
확장자 .txt 파일에서 마우스 우측버튼 누를때 나오는 메뉴에 원하는 기능을 추가한다.
(VS2008 기준)
--------------
1. ATL 프로젝트를 하나 생성한다. ( 프로젝트명 : MyContextMenu )
2. 응용프로그램 설정에서 "프록시/스텁 코드 병합 허용"에 체크를 해준다.
3. 클래스뷰에서 프로젝트를 선택하고 마우스 우측을 눌러서 "추가>클래스"를 선택한다.
4. ATL 단순 개체를 선택하고 "추가" 버튼을 클릭한다.
5. 약식이름에 MyContextMenu 를 입력한다.(나머지는 자동으로 채워질텐데 그냥 둔다.)
6. MyContextMenu.h 파일을 열어서 아래와 같이 인클루드 시킨다.
#include <shlobj.h>#include <comdef.h>
7. CMyContextMenu 클래스가 상속받는 인터페이스 목록에 다음 두개를 추가해준다.
public IShellExtInit,
public IContextMenu
8. BEGIN_COM_MAP 에 다음 두 항목을 추가해준다.
COM_INTERFACE_ENTRY(IShellExtInit)
COM_INTERFACE_ENTRY(IContextMenu)
9. 두개의 인터페이스(IShellExtInit, IContextMenu)가 구현해줘야 하는 함수들을 선언해준다.
public:
// IShellExtInit
STDMETHOD(Initialize)(LPCITEMIDLIST, LPDATAOBJECT, HKEY);
public:
// IContextMenu
STDMETHOD(GetCommandString)(UINT, UINT, UINT*, LPSTR, UINT);
STDMETHOD(InvokeCommand)(LPCMINVOKECOMMANDINFO);
STDMETHOD(QueryContextMenu)(HMENU, UINT, UINT, UINT, UINT);
10. 예제로 만드는 프로젝트에서 쓰일 변수 하나도 추가해준다.
public:TCHAR m_szFile[MAX_PATH];
11. MyContextMenu.cpp 파일을 열어서 해당 함수를 아래와 같이 구현해준다.
// IShellExtInit
HRESULT CMyContextMenu::Initialize (
LPCITEMIDLIST pidlFolder,
LPDATAOBJECT pDataObj,
HKEY hProgID )
{
FORMATETC fmt = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
STGMEDIUM stg = { TYMED_HGLOBAL };
HDROP hDrop;
// Look for CF_HDROP data in the data object.
if ( FAILED( pDataObj->GetData ( &fmt, &stg )))
{
// Nope! Return an "invalid argument" error back to Explorer.
return E_INVALIDARG;
}
// Get a pointer to the actual data.
hDrop = (HDROP) GlobalLock ( stg.hGlobal );
// Make sure it worked.
if ( NULL == hDrop )
{
return E_INVALIDARG;
}
UINT uNumFiles = DragQueryFile ( hDrop, 0xFFFFFFFF, NULL, 0 );
if ( 0 == uNumFiles )
{
GlobalUnlock ( stg.hGlobal );
ReleaseStgMedium ( &stg );
return E_INVALIDARG;
}
HRESULT hr = S_OK;
// Get the name of the first file and store it in our member variable m_szFile.
if ( 0 == DragQueryFile ( hDrop, 0, m_szFile, MAX_PATH ))
{
hr = E_INVALIDARG;
}
GlobalUnlock ( stg.hGlobal );
ReleaseStgMedium ( &stg );
return hr;
}
HRESULT CMyContextMenu::QueryContextMenu (
HMENU hmenu,
UINT uMenuIndex,
UINT uidFirstCmd,
UINT uidLastCmd,
UINT uFlags )
{
// If the flags include CMF_DEFAULTONLY then we shouldn't do anything.
if ( uFlags & CMF_DEFAULTONLY )
{
return MAKE_HRESULT ( SEVERITY_SUCCESS, FACILITY_NULL, 0 );
}
InsertMenu ( hmenu, uMenuIndex, MF_BYPOSITION, uidFirstCmd, _T("메뉴에 나타날 문자열") );
return MAKE_HRESULT ( SEVERITY_SUCCESS, FACILITY_NULL, 1 );
}
#include <atlconv.h> // for ATL string conversion macros
HRESULT CMyContextMenu::GetCommandString (
UINT idCmd,
UINT uFlags,
UINT* pwReserved,
LPSTR pszName,
UINT cchMax )
{
USES_CONVERSION;
// Check idCmd, it must be 0 since we have only one menu item.
if ( 0 != idCmd )
return E_INVALIDARG;
// If Explorer is asking for a help string, copy our string into the
// supplied buffer.
if ( uFlags & GCS_HELPTEXT )
{
LPCTSTR szText = _T("마우스를 가져다 댔을 때 상태창에 뜨는 문자열");
if ( uFlags & GCS_UNICODE )
{
// We need to cast pszName to a Unicode string, and then use the
// Unicode string copy API.
lstrcpynW ( (LPWSTR) pszName, T2CW(szText), cchMax );
}
else
{
// Use the ANSI string copy API to return the help string.
lstrcpynA ( pszName, T2CA(szText), cchMax );
}
return S_OK;
}
return E_INVALIDARG;
}
HRESULT CMyContextMenu::InvokeCommand ( LPCMINVOKECOMMANDINFO pCmdInfo )
{
// If lpVerb really points to a string, ignore this function call and bail out.
if ( 0 != HIWORD( pCmdInfo->lpVerb ))
return E_INVALIDARG;
// Get the command index - the only valid one is 0.
switch ( LOWORD( pCmdInfo->lpVerb ))
{
case 0:
{
TCHAR szMsg [MAX_PATH + 32];
wsprintf ( szMsg, _T("(메뉴 선택시처리되는 곳)선택된 파일:\n\n%s"), m_szFile );
MessageBox ( pCmdInfo->hwnd, szMsg, _T("SimpleShlExt"),
MB_ICONINFORMATION );
return S_OK;
}
break;
default:
return E_INVALIDARG;
break;
}
}
12. 솔루션탐색기에 보면 "리소스 파일" 항목에 MyContextMenu.rgs 파일을 볼수가 있는데 더블클릭하여 오픈하여 아래 줄을 추가해준다. ( HKCR 괄호 안에 같이 넣어준다. )
NoRemove txtfile
{
NoRemove ShellEx
{
NoRemove ContextMenuHandlers
{
ForceRemove SimpleShlExt = s '클래스아이디부분'
}
}
}
클래스아이디 부분은 바로 위에 'TypeLib' 부분에 나오는 클래스아이디로 바꿔준다.
13. 컴파일하여 regsvr32 로 등록해주면 확장자가 .txt인 파일에서 마우스 우측버튼을 누르면 "메뉴에 나타날 문자열" 이란 메뉴가 추가된 것을 알수 있고 클릭하면 파일의 전체경로를 보여준다.
(상세 소슴코드 설명은 생략)
[출처] Shell-Extension : Context menu 제어|작성자 김기용
'프로그래밍 팁 > etc' 카테고리의 다른 글
my_strtok_s 구현 (0) | 2011.03.24 |
---|---|
컨텍스트 정보 (0) | 2011.03.18 |
원격 네트워크 MAC주소 구하기 (0) | 2011.03.04 |
GetAdaptersInfo를 이용한 네트워크 정보 추출 (0) | 2011.03.04 |
DLL에서 다이얼로그 띄우기[핵심] (4) | 2011.01.26 |