Share via


IContextMenu 인터페이스를 구현하는 방법

IContextMenu 는 가장 강력하지만 구현할 가장 복잡한 인터페이스이기도 합니다. 정적 동사 메서드 중 하나를 사용하여 동사를 구현하는 것이 좋습니다. 자세한 내용은 정적 또는 동적 바로 가기 메뉴 메서드 선택을 참조하세요. IContextMenu 에는 여기서 자세히 설명하는 GetCommandString, InvokeCommandQueryContextMenu의 세 가지 메서드가 있습니다.

알아야 하는 작업

기술

  • C++

사전 요구 사항

  • 정적 동사
  • 바로 가기 메뉴

지침

IContextMenu::GetCommandString 메서드

처리기의 IContextMenu::GetCommandString 메서드는 동사의 정식 이름을 반환하는 데 사용됩니다. 이 메서드는 선택 사항입니다. Windows XP 및 이전 버전의 Windows에서 Windows Explorer 상태 표시줄이 있는 경우 이 메서드는 메뉴 항목의 상태 표시줄에 표시되는 도움말 텍스트를 검색하는 데 사용됩니다.

idCmd 매개 변수는 IContextMenu::QueryContextMenu가 호출되었을 때 정의된 명령의 식별자 오프셋을 보유합니다. 도움말 문자열이 요청되면 uFlagsGCS_HELPTEXTW 설정됩니다. 도움말 문자열을 pszName 버퍼에 복사하여 PWSTR로 캐스팅합니다. 동사 문자열은 uFlagsGCS_VERBW 설정하여 요청됩니다. 도움말 문자열과 마찬가지로 적절한 문자열 을 pszName에 복사합니다. GCS_VALIDATEAGCS_VALIDATEW 플래그는 바로 가기 메뉴 처리기에서 사용되지 않습니다.

다음 예제에서는 이 항목의 IContextMenu::QueryContextMenu 메서드 섹션에 제공된 QueryContextMenu 예제에 해당하는 GetCommandString의 간단한 구현을 보여 줍니다. 처리기는 하나의 메뉴 항목만 추가하므로 반환할 수 있는 문자열 집합이 하나만 있습니다. 메서드는 idCmd 가 유효한지 테스트하고 이 경우 요청된 문자열을 반환합니다.

StringCchCopy 함수는 요청된 문자열을 pszName에 복사하여 복사된 문자열이 cchName에 지정된 버퍼의 크기를 초과하지 않도록 하는 데 사용됩니다. 이 예제에서는 Windows 2000 이후 Windows Explorer 사용되었기 때문에 uFlags의 유니코드 값에 대해서만 지원을 구현합니다.

IFACEMETHODIMP CMenuExtension::GetCommandString(UINT idCommand, 
                                                UINT uFlags, 
                                                UINT *pReserved, 
                                                PSTR pszName, 
                                                UINT cchName)
{
    HRESULT hr = E_INVALIDARG;

    if (idCommand == IDM_DISPLAY)
    {
        switch (uFlags)
        {
            case GCS_HELPTEXTW:
                // Only useful for pre-Vista versions of Windows that 
                // have a Status bar.
                hr = StringCchCopyW(reinterpret_cast<PWSTR>(pszName), 
                                    cchName, 
                                    L"Display File Name");
                break; 

            case GCS_VERBW:
                // GCS_VERBW is an optional feature that enables a caller
                // to discover the canonical name for the verb that is passed in
                // through idCommand.
                hr = StringCchCopyW(reinterpret_cast<PWSTR>(pszName), 
                                    cchName, 
                                    L"DisplayFileName");
                break; 
        }
    }
    return hr;
}

IContextMenu::InvokeCommand 메서드

이 메서드는 사용자가 메뉴 항목을 클릭하여 처리기에 연결된 명령을 실행하도록 지시할 때 호출됩니다. pici 매개 변수는 명령을 실행하는 데 필요한 정보를 포함하는 구조를 가리킵니다.

pici는 Shlobj.h에서 CMINVOKECOMMANDINFO 구조체로 선언되지만 실제로는 CMINVOKECOMMANDINFOEX 구조를 가리키는 경우가 많습니다. 이 구조체는 CMINVOKECOMMANDINFO 의 확장 버전이며 유니코드 문자열을 전달할 수 있는 몇 가지 추가 멤버가 있습니다.

picicbSize 멤버를 확인하여 전달된 구조를 확인합니다. CMINVOKECOMMANDINFOEX 구조체이고 fMask 멤버에 CMIC_MASK_UNICODE 플래그 집합이 있는 경우 piciCMINVOKECOMMANDINFOEX로 캐스팅합니다. 이렇게 하면 애플리케이션이 구조체의 마지막 5개 멤버에 포함된 유니코드 정보를 사용할 수 있습니다.

구조체의 lpVerb 또는 lpVerbW 멤버는 실행할 명령을 식별하는 데 사용됩니다. 명령은 다음 두 가지 방법 중 하나로 식별됩니다.

  • 명령의 동사 문자열 기준
  • 명령의 식별자 오프셋 기준

이러한 두 경우를 구분하려면 ANSI 케이스의 경우 lpVerb의 상위 단어 또는 유니코드 케이스의 경우 lpVerbW를 검사. 상위 단어가 0이 아닌 경우 lpVerb 또는 lpVerbW 는 동사 문자열을 보유합니다. 상위 단어가 0이면 명령 오프셋이 lpVerb의 하위 단어에 있습니다.

다음 예제에서는 이 섹션 전후에 제공된 IContextMenu::QueryContextMenu 및 IContextMenu::GetCommandString 예제에 해당하는 IContextMenu::InvokeCommand의 간단한 구현을 보여 줍니다. 메서드는 먼저 전달되는 구조를 결정합니다. 그런 다음, 명령이 오프셋 또는 동사로 식별되는지 여부를 결정합니다. lpVerb 또는 lpVerbW에 유효한 동사 또는 오프셋이 있는 경우 메서드는 메시지 상자를 표시합니다.

STDMETHODIMP CShellExtension::InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi)
{
    BOOL fEx = FALSE;
    BOOL fUnicode = FALSE;

    if(lpcmi->cbSize == sizeof(CMINVOKECOMMANDINFOEX))
    {
        fEx = TRUE;
        if((lpcmi->fMask & CMIC_MASK_UNICODE))
        {
            fUnicode = TRUE;
        }
    }

    if( !fUnicode && HIWORD(lpcmi->lpVerb))
    {
        if(StrCmpIA(lpcmi->lpVerb, m_pszVerb))
        {
            return E_FAIL;
        }
    }

    else if( fUnicode && HIWORD(((CMINVOKECOMMANDINFOEX *) lpcmi)->lpVerbW))
    {
        if(StrCmpIW(((CMINVOKECOMMANDINFOEX *)lpcmi)->lpVerbW, m_pwszVerb))
        {
            return E_FAIL;
        }
    }

    else if(LOWORD(lpcmi->lpVerb) != IDM_DISPLAY)
    {
        return E_FAIL;
    }

    else
    {
        MessageBox(lpcmi->hwnd,
                   "The File Name",
                   "File Name",
                   MB_OK|MB_ICONINFORMATION);
    }

    return S_OK;
}

IContextMenu::QueryContextMenu 메서드

셸은 IContextMenu::QueryContextMenu 를 호출하여 바로 가기 메뉴 처리기가 메뉴에 메뉴 항목을 추가할 수 있도록 합니다. hmenu 매개 변수의 HMENU 핸들을 전달합니다. indexMenu 매개 변수는 추가할 첫 번째 메뉴 항목에 사용할 인덱스로 설정됩니다.

처리기에서 추가된 모든 메뉴 항목에는 idCmdFirstidCmdLast 매개 변수의 값 사이에 속하는 식별자가 있어야 합니다. 일반적으로 첫 번째 명령 식별자는 idCmdFirst로 설정되며, 각 추가 명령에 대해 1씩 증가합니다. 이 방법을 사용하면 idCmdLast 를 초과하지 않고 Shell이 둘 이상의 처리기를 호출하는 경우 사용 가능한 식별자 수를 최대화할 수 있습니다.

항목 식별자의 명령 오프셋idCmdFirst의 식별자와 값 간의 차이입니다. 셸이 이후에 IContextMenu::GetCommandString 또는 IContextMenu::InvokeCommand를 호출하는 경우 오프셋을 사용하여 항목을 식별할 수 있으므로 처리기가 바로 가기 메뉴에 추가하는 각 항목의 오프셋을 저장합니다.

또한 추가하는 각 명령에 동사를 할당해야 합니다. 동사는 InvokeCommand 가 호출될 때 오프셋 대신 명령을 식별하는 데 사용할 수 있는 문자열입니다. 또한 ShellExecuteEx와 같은 함수에서 바로 가기 메뉴 명령을 실행하는 데도 사용됩니다.

바로 가기 메뉴 처리기와 관련된 uFlags 매개 변수를 통해 전달할 수 있는 세 가지 플래그가 있습니다. 이 내용은 다음 표에 설명되어 있습니다.

플래그 설명
CMF_DEFAULTONLY 사용자는 일반적으로 개체를 두 번 클릭하여 기본 명령을 선택했습니다. IContextMenu::QueryContextMenu 는 메뉴를 수정하지 않고 컨트롤을 셸로 반환해야 합니다.
CMF_NODEFAULT 메뉴의 항목이 기본 항목이 아니어야 합니다. 메서드는 메뉴에 해당 명령을 추가해야 합니다.
CMF_NORMAL 바로 가기 메뉴가 정상적으로 표시됩니다. 메서드는 메뉴에 해당 명령을 추가해야 합니다.

 

InsertMenu 또는 InsertMenuItem을 사용하여 메뉴 항목을 목록에 추가합니다. 그런 다음 심각도가 SEVERITY_SUCCESS 설정된 HRESULT 값을 반환합니다. 코드 값을 할당된 가장 큰 명령 식별자의 오프셋과 하나(1)로 설정합니다. 예를 들어 idCmdFirst 가 5로 설정되고 명령 식별자가 5, 7 및 8인 메뉴에 세 개의 항목을 추가한다고 가정합니다. 반환 값은 MAKE_HRESULT(SEVERITY_SUCCESS, 0, 8 + 1)이어야 합니다.

다음 예제에서는 단일 명령을 삽입하는 QueryContextMenu 의 간단한 구현을 보여 줍니다. 명령에 대한 식별자 오프셋은 0으로 설정된 IDM_DISPLAY. m_pszVerbm_pwszVerb 변수는 연결된 언어 독립적 동사 문자열을 ANSI 및 유니코드 형식으로 저장하는 데 사용되는 프라이빗 변수입니다.

#define IDM_DISPLAY 0

STDMETHODIMP CMenuExtension::QueryContextMenu(HMENU hMenu,
                                              UINT indexMenu,
                                              UINT idCmdFirst,
                                              UINT idCmdLast,
                                              UINT uFlags)
{
    HRESULT hr;
    
    if(!(CMF_DEFAULTONLY & uFlags))
    {
        InsertMenu(hMenu, 
                   indexMenu, 
                   MF_STRING | MF_BYPOSITION, 
                   idCmdFirst + IDM_DISPLAY, 
                   "&Display File Name");

    
        
        hr = StringCbCopyA(m_pszVerb, sizeof(m_pszVerb), "display");
        hr = StringCbCopyW(m_pwszVerb, sizeof(m_pwszVerb), L"display");

        return MAKE_HRESULT(SEVERITY_SUCCESS, 0, USHORT(IDM_DISPLAY + 1));
    }

    return MAKE_HRESULT(SEVERITY_SUCCESS, 0, USHORT(0));}

설명

다른 동사 구현 작업은 바로 가기 메뉴 처리기 만들기를 참조하세요.