如何在上下文菜单中制作级联子菜单 [英] How to make cascade submenus inside context menu

查看:71
本文介绍了如何在上下文菜单中制作级联子菜单的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



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



PS代码在本教程中使用如何使用子菜单在上下文菜单外壳扩展 [ ^ ]



Hello im trying to get cascade window inside context menu in shell extension. I add two submenus inside context menu of .dll extension, but want to make one cascade submenu (i like to open first menu and after clicking on some menu inside, want to open next submenu).

How to get cascade submenus from this code, where did i make mistake?

P.S. Code is used from this tutorial How to Use Submenus in a Context Menu Shell Extension[^]

// 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;
        }
}

推荐答案

子菜单只是一种菜单项,想想它就像一个菜单项从菜单项类派生的类。

您将子菜单插入菜单的方式与将子菜单插入菜单的方式完全相同,就像它是菜单项一样,通过调用到 InsertMenuItem 。您可以从已有的示例代码和API调用的F1帮助中计算出血腥细节。
A sub menu is just a kind of menu item, think of it like a class derived from the menu item class.
You insert a sub menu into your menu in exactly the same way you insert your sub menu into their menu, just as if it were a menu item, with a call to InsertMenuItem. You can work out the gory details from the sample code you already have and the F1 help for the API calls.


从Matthew Faithfull回答我们得到以下代码,在现有子菜单下创建子菜单。



From Matthew Faithfull answer we get below code that create sub menu under existing sub menu.

// 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;
        }
}


这篇关于如何在上下文菜单中制作级联子菜单的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆