使用c ++在上下文菜单shell扩展中的级联子菜单

时间:2013-02-10 21:57:11

标签: c++ windows shell contextmenu submenu

您好我正在尝试在shell扩展中的上下文菜单中获取级联窗口。我在.dll扩展名的上下文菜单中添加了两个子菜单,但想要制作一个级联子菜单(我想打开第一个菜单,点击里面的一些菜单后,想要打开下一个子菜单)。

如何从此代码获取级联子菜单,我在哪里犯了错误?

    // OpenWithCtxMenuExt.cpp : Implementation of COpenWithCtxMenuExt

#include "stdafx.h"
#include "OpenWithExt.h"
#include "OpenWithCtxMenuExt.h"

#pragma comment(lib,"shlwapi")

/////////////////////////////////////////////////////////////////////////////
// COpenWithCtxMenuExt

HRESULT COpenWithCtxMenuExt::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;

    // Sanity check - make sure there is at least one filename.
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_szSelectedFile, MAX_PATH ))
        hr = E_INVALIDARG;
    else
        {
        // Quote the name if it contains spaces (needed so the cmd line is built properly)
        PathQuoteSpaces ( m_szSelectedFile );
        }

    GlobalUnlock ( stg.hGlobal );
    ReleaseStgMedium ( &stg );

    return hr;
}

HRESULT COpenWithCtxMenuExt::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 );

    // First, create and populate a submenu.
HMENU hSubmenu = CreatePopupMenu();
HMENU hSubmenu1 = CreatePopupMenu();
UINT uID = uidFirstCmd;

    InsertMenu ( hSubmenu, 0, MF_BYPOSITION, uID++, _T("&Notepad") );
    InsertMenu ( hSubmenu, 1, MF_BYPOSITION, uID++, _T("&Internet Explorer") );
    InsertMenu ( hSubmenu, 2, MF_BYPOSITION, uID++, _T("&Mspaint") );
    InsertMenu ( hSubmenu, 3, MF_BYPOSITION, uID++, _T("&Pop") );

// provjeriti uID da se ne zbraja
    InsertMenu ( hSubmenu1, 0, MF_BYPOSITION, uID++, _T("&Notepad") );
    InsertMenu ( hSubmenu1, 1, MF_BYPOSITION, uID++, _T("&Mspaint") );


    // Insert the submenu into the ctx menu provided by Explorer.
MENUITEMINFO mii = { sizeof(MENUITEMINFO) };

    mii.fMask = MIIM_SUBMENU | /*MIIM_STRING*/ 0x00000040 | MIIM_ID;
    mii.wID = uID++;
    mii.hSubMenu = hSubmenu;
    mii.dwTypeData = _T("C&P Open With");

    InsertMenuItem ( hmenu, uMenuIndex, TRUE, &mii );

      // Insert the submenu into the ctx menu provided by Explorer.
MENUITEMINFO mii1 = { sizeof(MENUITEMINFO) };

    mii1.fMask = MIIM_SUBMENU | /*MIIM_STRING*/ 0x00000040 | MIIM_ID;
    mii1.wID = uID++;
    mii1.hSubMenu = hSubmenu;
    mii1.dwTypeData = _T("C&P pod_folder");

    InsertMenuItem ( hmenu, uMenuIndex, TRUE, &mii1 );

    return MAKE_HRESULT ( SEVERITY_SUCCESS, FACILITY_NULL, uID - uidFirstCmd );
}

HRESULT COpenWithCtxMenuExt::GetCommandString ( UINT  idCmd,      UINT uFlags,
                                                UINT* pwReserved, LPSTR pszName,
                                                UINT  cchMax )
{
USES_CONVERSION;

    // Check idCmd, it must be 0 or 1 since we have two menu items.
    if ( idCmd > 3 )
        return E_INVALIDARG;

    // If Explorer is asking for a help string, copy our string into the
    // supplied buffer.
    if ( uFlags & GCS_HELPTEXT )
        {
        LPCTSTR szNotepadText = _T("Open the selected file in Notepad");
        LPCTSTR szIEText = _T("Open the selected file in Internet Explorer");
        LPCTSTR szPintText = _T("Open the selected file with Mspaint");
        LPCTSTR szPopText = _T("Popout");

        LPCTSTR szNotepad1Text = _T("Open the selected file in Notepad");
        LPCTSTR szPint1Text = _T("Open the selected file with Mspaint");

        //LPCTSTR pszText = (0 == idCmd) ? szNotepadText : szIEText;
        LPCTSTR pszText;
        if(idCmd == 0){
            pszText = szNotepadText;
        }
        if(idCmd == 1){
            pszText = szIEText;
        }
        if(idCmd == 2){
            pszText = szPintText;
        }
        if(idCmd == 3){
            pszText = szPopText;
        }       
        if(idCmd == 4){
            pszText = szNotepad1Text;
        }       
        if(idCmd == 5){
            pszText = szPint1Text;
        }

        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(pszText), cchMax );
            }
        else
            {
            // Use the ANSI string copy API to return the help string.
            lstrcpynA ( pszName, T2CA(pszText), cchMax );
            }

        return S_OK;
        }

    return E_INVALIDARG;
}

HRESULT COpenWithCtxMenuExt::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.
    switch ( LOWORD( pCmdInfo->lpVerb ))
        {
        case 0:
            {
            ShellExecute ( pCmdInfo->hwnd, _T("open"), _T("notepad.exe"),
                           m_szSelectedFile, NULL, SW_SHOW );

            return S_OK;
            }
        break;

        case 1:
            {
            ShellExecute ( pCmdInfo->hwnd, _T("open"), _T("iexplore.exe"),
                           m_szSelectedFile, NULL, SW_SHOW );

            return S_OK;
            }
        break;

        case 2:
            {
            ShellExecute ( pCmdInfo->hwnd, _T("open"), _T("mspaint.exe"),
                           m_szSelectedFile, NULL, SW_SHOW );

            return S_OK;
            }
        break;

        case 3:
            {
            ShellExecute ( pCmdInfo->hwnd, _T("open"), _T("mspaint.exe"),
                           m_szSelectedFile, NULL, SW_SHOW );

            return S_OK;
            }
        break;

        case 4:
            {
            ShellExecute ( pCmdInfo->hwnd, _T("open"), _T("notepad.exe"),
                           m_szSelectedFile, NULL, SW_SHOW );

            return S_OK;
            }
        break;

        case 5:
            {
            ShellExecute ( pCmdInfo->hwnd, _T("open"), _T("mspaint.exe"),
                           m_szSelectedFile, NULL, SW_SHOW );

            return S_OK;
            }
        break;

        default:
            return E_INVALIDARG;
        break;
        }
}

1 个答案:

答案 0 :(得分:1)

经过一段时间后,找到了在现有上下文菜单中制作级联上下文菜单的解决方案......这里是代码:

    // OpenWithCtxMenuExt.cpp : Implementation of COpenWithCtxMenuExt

#include "stdafx.h"
#include "OpenWithExt.h"
#include "OpenWithCtxMenuExt.h"

#pragma comment(lib,"shlwapi")

/////////////////////////////////////////////////////////////////////////////
// COpenWithCtxMenuExt

HRESULT COpenWithCtxMenuExt::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;

    // Sanity check - make sure there is at least one filename.
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_szSelectedFile, MAX_PATH ))
        hr = E_INVALIDARG;
    else
        {
        // Quote the name if it contains spaces (needed so the cmd line is built properly)
        PathQuoteSpaces ( m_szSelectedFile );
        }

    GlobalUnlock ( stg.hGlobal );
    ReleaseStgMedium ( &stg );

    return hr;
}

HRESULT COpenWithCtxMenuExt::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 );

    // First, create and populate a submenu.
HMENU hSubmenu = CreatePopupMenu();
HMENU hSub = CreatePopupMenu();
UINT uID = uidFirstCmd;

    InsertMenu ( hSubmenu, 0, MF_BYPOSITION, uID++, _T("&Notepad") );
    InsertMenu ( hSubmenu, 1, MF_BYPOSITION, uID++, _T("&Internet Explorer") );
    InsertMenu ( hSubmenu, 2, MF_BYPOSITION, uID++, _T("&Mspaint") );
    InsertMenu ( hSubmenu, 3, MF_BYPOSITION, uID++, _T("&Pop") );

    InsertMenu ( hSub, 4, MF_BYPOSITION, uID++, _T("&Case") );
    InsertMenu ( hSub, 5, MF_BYPOSITION, uID++, _T("&Case") );

    // Insert the submenu into the ctx menu provided by Explorer.
MENUITEMINFO mii = { sizeof(MENUITEMINFO) };

    mii.fMask = MIIM_SUBMENU | /*MIIM_STRING*/ 0x00000040 | MIIM_ID;
    mii.wID = uID++;
    mii.hSubMenu = hSubmenu;
    mii.dwTypeData = _T("Open With&x");

    InsertMenuItem ( hmenu, uMenuIndex, TRUE, &mii );

    mii.hSubMenu = hSub;
    mii.dwTypeData = _T("Novi Subm&enu");

    InsertMenuItem ( hSubmenu, uMenuIndex, TRUE, &mii );

    return MAKE_HRESULT ( SEVERITY_SUCCESS, FACILITY_NULL, uID - uidFirstCmd );
}


HRESULT COpenWithCtxMenuExt::GetCommandString ( UINT  idCmd,      UINT uFlags,
                                                UINT* pwReserved, LPSTR pszName,
                                                UINT  cchMax )
{
USES_CONVERSION;

    // Check idCmd, it must be 0 or 1 since we have two menu items.
    if ( idCmd > 4 )
        return E_INVALIDARG;

    // If Explorer is asking for a help string, copy our string into the
    // supplied buffer.
    if ( uFlags & GCS_HELPTEXT )
        {
        LPCTSTR szNotepadText = _T("Open the selected file in Notepad");
        LPCTSTR szIEText = _T("Open the selected file in Internet Explorer");
        LPCTSTR szPintText = _T("Open the selected file with Mspaint");
        LPCTSTR szPopText = _T("Popout");
        //LPCTSTR pszText = (0 == idCmd) ? szNotepadText : szIEText;
        LPCTSTR pszText;
        if(idCmd == 0){
            pszText = szNotepadText;
        }
        if(idCmd == 1){
            pszText = szIEText;
        }
        if(idCmd == 2){
            pszText = szPintText;
        }

        if(idCmd == 3){
            pszText = szPopText;
        }

        if(idCmd == 4){
            pszText = szPopText;
        }



        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(pszText), cchMax );
            }
        else
            {
            // Use the ANSI string copy API to return the help string.
            lstrcpynA ( pszName, T2CA(pszText), cchMax );
            }

        return S_OK;
        }

    return E_INVALIDARG;
}

HRESULT COpenWithCtxMenuExt::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.
    switch ( LOWORD( pCmdInfo->lpVerb ))
        {
        case 0:
            {
            ShellExecute ( pCmdInfo->hwnd, _T("open"), _T("notepad.exe"),
                           m_szSelectedFile, NULL, SW_SHOW );

            return S_OK;
            }
        break;

        case 1:
            {
            ShellExecute ( pCmdInfo->hwnd, _T("open"), _T("iexplore.exe"),
                           m_szSelectedFile, NULL, SW_SHOW );

            return S_OK;
            }
        break;

        case 2:
            {
            ShellExecute ( pCmdInfo->hwnd, _T("open"), _T("mspaint.exe"),
                           m_szSelectedFile, NULL, SW_SHOW );

            return S_OK;
            }
        break;

            case 4:
            {
                MessageBox(0, "New command from sub menu", "Case 4", 0);
            return S_OK;
            }
        break;

        case 5:
            {
                MessageBox(0, "New second command from sub menu", "Case 5", 0);
            return S_OK;
            }
        break;

        default:
            return E_INVALIDARG;
        break;
        }
}