아래는 김기용님이 작성하신 내용입니다.
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인 파일에서 마우스 우측버튼을 누르면 "메뉴에 나타날 문자열" 이란 메뉴가 추가된 것을 알수 있고 클릭하면 파일의 전체경로를 보여준다.

(상세 소슴코드 설명은 생략)

Posted by 띠깜
,