C++、MFC/Win32调用Windows系统桌面右键菜单和文件右键菜单方法

xingyun86 2021-12-28 844

C++、MFC/Win32调用Windows系统桌面右键菜单和文件右键菜单方法

调用方法:

CShellContextMenu().ShowRightMenu(this, linkItemList.at(lvi.lParam).path.c_str());

工具类代码如下:

class CShellContextMenu
{
#define CMD_ID_MIN 0x0001
#define CMD_ID_MAX 0xFFFF
    
public:
    static IContextMenu2* IContext2(BOOL bGet = TRUE, IContextMenu2* pIContextMenu2 = NULL)
    {
        static IContextMenu2* G_pIContext2 = NULL;
        if (bGet == FALSE)
        {
            G_pIContext2 = pIContextMenu2;
        }
        return G_pIContext2;
    }
    static IContextMenu3* IContext3(BOOL bGet = TRUE, IContextMenu3* pIContextMenu3 = NULL)
    {
        static IContextMenu3* G_pIContext3 = NULL;
        if (bGet == FALSE)
        {
            G_pIContext3 = pIContextMenu3;
        }
        return G_pIContext3;
    }
    CShellContextMenu() {
        m_pIShellFolder = NULL;
        m_pidlArray = NULL;
        m_menu.CreatePopupMenu();  // create the popupmenu (its empty)
    }
    virtual ~CShellContextMenu() {
        Cleanup();
        m_menu.DestroyMenu();
    }
    void Cleanup()
    {
        // free all allocated datas
        if (m_pIShellFolder != NULL)
        {
            if (m_bDelete)
            {
                m_pIShellFolder->Release();
            }
            m_pIShellFolder = NULL;
        }
        if (m_pidlArray != NULL)
        {
            FreePIDLArray(m_pidlArray);
            m_pidlArray = NULL;
        }
    }
public:
    void ShowRightMenu(CWnd *pWnd, const CStringW & strFilePath)
    {
        CShellContextMenu shellMenu = {};
        DWORD dwMsgPos = ::GetMessagePos();
        shellMenu.SetObjects(strFilePath);
        //设置菜单弹出坐标
        UINT cmd = shellMenu.ShowContextMenu(pWnd, CPoint(LOWORD(dwMsgPos), HIWORD(dwMsgPos)));
    }
    CMenu& GetMenu()
    {
        return (m_menu);
    }
    void SetObjects(IShellFolder* pIShellFolder, LPITEMIDLIST pidlItem)
    {
        Cleanup();
        m_pIShellFolder = pIShellFolder;
        m_pidlArray = (LPITEMIDLIST*)malloc(sizeof(LPITEMIDLIST));
        if (m_pidlArray != NULL)
        {
            m_pidlArray[0] = CopyPIDL(pidlItem);
            m_nItems = 1;
            m_bDelete = FALSE;    // indicates wheter m_psfFolder should be deleted by CShellContextMenu
        }
    }
    void SetObjects(IShellFolder* pIShellFolder, LPITEMIDLIST* pidlArray, int nItemCount)
    {
        Cleanup();
        m_pIShellFolder = pIShellFolder;
        m_pidlArray = (LPITEMIDLIST*)malloc(nItemCount * sizeof(LPITEMIDLIST));
        if (m_pidlArray != NULL)
        {
            for (int i = 0; i < nItemCount; i++)
            {
                m_pidlArray[i] = CopyPIDL(pidlArray[i]);
            }
            m_nItems = nItemCount;
            m_bDelete = FALSE;    // indicates wheter m_psfFolder should be deleted by CShellContextMenu
        }
    }
    void SetObjects(LPITEMIDLIST pidl)
    {
        LPMALLOC lpMalloc = NULL;
        LPITEMIDLIST pidlItem = NULL;
        SHGetMalloc(&lpMalloc);
        if (lpMalloc != NULL)
        {
            Cleanup();
            // full qualified PIDL is passed so we need
            // its parent IShellFolder interface and its relative PIDL to that
            SHBindToParent((LPCITEMIDLIST)pidl, IID_IShellFolder, (void**)&m_pIShellFolder, (LPCITEMIDLIST*)&pidlItem);
            if (pidlItem != NULL)
            {
                m_pidlArray = (LPITEMIDLIST*)malloc(sizeof(LPITEMIDLIST));  // allocate ony for one elemnt
                if (m_pidlArray != NULL)
                {
                    m_pidlArray[0] = CopyPIDL(pidlItem);
                    // now free pidlItem via IMalloc interface (but not m_psfFolder, that we need later
                    lpMalloc->Free(pidlItem);
                    pidlItem = NULL;
                    m_nItems = 1;
                    m_bDelete = TRUE; // indicates that m_psfFolder should be deleted by CShellContextMenu
                }
            }
            lpMalloc->Release();
            lpMalloc = NULL;
        }
    }
    void SetObjects(CStringW strObject)
    {
        // only one object is passed
        CStringArray strArray;
        strArray.Add(strObject);   // create a CStringArray with one element
        SetObjects(strArray);      // and pass it to SetObjects (CStringArray &strArray)
                                    // for further processing
    }
    void SetObjects(const CStringArray& strArray)
    {
        LPMALLOC lpMalloc = NULL;
        LPITEMIDLIST pidl = NULL;
        LPITEMIDLIST pidlItem = NULL; // relative pidl
        IShellFolder* pIShellFolder = NULL;
        LPITEMIDLIST* m_pidlArrayBak = NULL;
        IShellFolder* pIShellFolderDesktop = NULL;
        Cleanup();
        // get interface to IMalloc (need to free the PIDLs allocated by the shell functions)
        SHGetMalloc(&lpMalloc);
        if (lpMalloc != NULL)
        {
            // get IShellFolder interface of Desktop (root of shell namespace)
            SHGetDesktopFolder(&pIShellFolderDesktop);   // needed to obtain full qualified pidl
            if (pIShellFolderDesktop != NULL)
            {
                // ParseDisplayName creates a PIDL from a file system path relative to the IShellFolder interface
                // but since we use the Desktop as our interface and the Desktop is the namespace root
                // that means that it's a fully qualified PIDL, which is what we need
                pIShellFolderDesktop->ParseDisplayName(NULL, 0, (LPWSTR)(LPCWSTR)strArray.GetAt(0), NULL, &pidl, NULL);
                if (pidl != NULL)
                {
                    // now we need the parent IShellFolder interface of pidl, and the relative PIDL to that interface
                    SHBindToParentEx(pidl, IID_IShellFolder, (void**)&m_pIShellFolder, NULL);
                    lpMalloc->Free(pidl);
                    pidl = NULL;
                    if (m_pIShellFolder != NULL)
                    {
                        // now we have the IShellFolder interface to the parent folder specified in the first element in strArray
                        // since we assume that all objects are in the same folder (as it's stated in the MSDN)
                        // we now have the IShellFolder interface to every objects parent folder
                        m_nItems = (int)strArray.GetSize();
                        for (int i = 0; i < m_nItems; i++)
                        {
                            pIShellFolderDesktop->ParseDisplayName(NULL, 0, (LPWSTR)(LPCWSTR)strArray.GetAt(i), NULL, &pidl, NULL);
                            m_pidlArrayBak = m_pidlArray;
                            m_pidlArray = (LPITEMIDLIST*)realloc(m_pidlArray, (i + 1) * sizeof(LPITEMIDLIST));
                            if (m_pidlArray != NULL)
                            {
                                // get relative pidl via SHBindToParent
                                SHBindToParentEx(pidl, IID_IShellFolder, (void**)&pIShellFolder, (LPCITEMIDLIST*)&pidlItem);
                                if (pIShellFolder != NULL)
                                {
                                    if (pidlItem != NULL)
                                    {
                                        m_pidlArray[i] = CopyPIDL(pidlItem);   // copy relative pidl to pidlArray
                                        free(pidlItem);
                                        pidlItem = NULL;
                                    }
                                    lpMalloc->Free(pidl);      // free pidl allocated by ParseDisplayName
                                    pIShellFolder->Release();
                                    pIShellFolder = NULL;
                                }
                            }
                            if (m_pidlArrayBak != NULL)
                            {
                                free(m_pidlArrayBak);
                                m_pidlArrayBak = NULL;
                            }
                        }
                    }
                    pIShellFolderDesktop->Release();
                    pIShellFolderDesktop = NULL;
                    m_bDelete = TRUE; // indicates that m_psfFolder should be deleted by CShellContextMenu
                }
            }
            lpMalloc->Release();
        }
    }
    BOOL ShowContextMenu(CWnd* pWnd, CPoint pt)
    {
        HRESULT hResult = S_FALSE;
        int nMenuType = 0;  // to know which version of IContextMenu is supported
        LPCONTEXTMENU pContextMenu = NULL; // common pointer to IContextMenu and higher version interface
        if (!GetContextMenu((void**)&pContextMenu, nMenuType))
        {
            return (FALSE); // something went wrong
        }
        //m_menu.DestroyMenu();
        //m_menu.CreatePopupMenu();
        
        // lets fill the our popupmenu  
        hResult = pContextMenu->QueryContextMenu(m_menu.m_hMenu, m_menu.GetMenuItemCount(), CMD_ID_MIN, CMD_ID_MAX, CMF_NORMAL | CMF_EXPLORE);
        // subclass window to handle menurelated messages in CShellContextMenu 
        WNDPROC OldWndProc = NULL;
        if (nMenuType > 1)  // only subclass if its version 2 or 3
        {
            OldWndProc = (WNDPROC)SetWindowLongPtrW(pWnd->m_hWnd, GWLP_WNDPROC, (LONG_PTR)HookWndProc);
            if (nMenuType == 2)
            {
                CShellContextMenu::IContext2(FALSE, (LPCONTEXTMENU2)pContextMenu);
            }
            else    // version 3
            {
                CShellContextMenu::IContext3(FALSE, (LPCONTEXTMENU3)pContextMenu);
            }
        }
        else
        {
            OldWndProc = NULL;
        }
        UINT idCommand = m_menu.TrackPopupMenu(TPM_RETURNCMD | TPM_LEFTALIGN | TPM_NOANIMATION | TPM_VCENTERALIGN, pt.x, pt.y, pWnd);
        if (OldWndProc) // unsubclass
        {
            SetWindowLongPtrW(pWnd->m_hWnd, GWLP_WNDPROC, (LONG_PTR)OldWndProc);
        }
        if (idCommand >= CMD_ID_MIN && idCommand <= CMD_ID_MAX) // see if returned idCommand belongs to shell menu entries
        {
            InvokeCommand(pContextMenu, idCommand - CMD_ID_MIN);   // execute related command
            idCommand = 0;
        }
        else
        {
            idCommand = -1;
        }
        pContextMenu->Release();
        CShellContextMenu::IContext2(FALSE, NULL);
        CShellContextMenu::IContext2(FALSE, NULL);
        return (idCommand);
    }
private:
    int m_nItems = 0;
    BOOL m_bDelete = FALSE;
    CMenu m_menu = {};
    IShellFolder* m_pIShellFolder = NULL;
    LPITEMIDLIST* m_pidlArray = NULL;
    void InvokeCommand(LPCONTEXTMENU pContextMenu, UINT idCommand)
    {
        CMINVOKECOMMANDINFO cmi = { 0 };
        cmi.cbSize = sizeof(CMINVOKECOMMANDINFO);
        cmi.lpVerb = (LPSTR)MAKEINTRESOURCE(idCommand);
        cmi.nShow = SW_SHOWNORMAL;
        pContextMenu->InvokeCommand(&cmi);
    }
    BOOL GetContextMenu(VOID** ppContextMenu, int& nMenuType)
    {
        LPCONTEXTMENU pContextMenu = NULL;
        *ppContextMenu = NULL;
        if (m_pIShellFolder == NULL)
        {
            return FALSE;
        }
        // first we retrieve the normal IContextMenu interface (every object should have it)
        m_pIShellFolder->GetUIObjectOf(NULL, m_nItems, (LPCITEMIDLIST*)m_pidlArray, IID_IContextMenu, NULL, (void**)&pContextMenu);
        if (pContextMenu != NULL)
        {
            // since we got an IContextMenu interface we can now obtain the higher version interfaces via that
            /*if (pContextMenu->QueryInterface(IID_IContextMenu3, ppContextMenu) == NOERROR)
            {
                nMenuType = 3;
            }
            else if (pContextMenu->QueryInterface(IID_IContextMenu2, ppContextMenu) == NOERROR)
            {
                nMenuType = 2;
            }
            if (*ppContextMenu)
            {
                pContextMenu->Release(); // we can now release version 1 interface, cause we got a higher one
                pContextMenu = NULL;
            }
            else*/
            {
                nMenuType = 1;
                *ppContextMenu = pContextMenu;  // since no higher versions were found
            }// redirect ppContextMenu to version 1 interface
        }
        else
        {
            return (FALSE); // something went wrong
        }
        return (TRUE); // success
    }
    BOOL SHBindToParentEx(LPCITEMIDLIST pidl, REFIID riid, VOID** ppv, LPCITEMIDLIST* ppidlLast)
    {
        BOOL bRet = FALSE;
        IShellFolder* pIShellFolderDesktop = NULL;
        IShellFolder* pIShellFolder = NULL;
        LPITEMIDLIST pidlParent = NULL;
        LPBYTE pRel = NULL;
        int nCount = 0;
        if (pidl != NULL && ppv != NULL)
        {
            SHGetDesktopFolder(&pIShellFolderDesktop);
            if (pIShellFolderDesktop != NULL)
            {
                nCount = GetPIDLCount(pidl);
                if (nCount > 0)    // desktop pidl of invalid pidl
                {
                    if (nCount == 1)    // desktop pidl
                    {
                        if (SUCCEEDED(pIShellFolderDesktop->QueryInterface(riid, ppv)))
                        {
                            if (ppidlLast)
                            {
                                *ppidlLast = CopyPIDL(pidl);
                                bRet = TRUE;
                            }
                        }
                    }
                    else
                    {
                        pRel = GetPIDLPos(pidl, nCount - 1);
                        pidlParent = CopyPIDL(pidl, (int)(pRel - (LPBYTE)pidl));
                        if (pidlParent != NULL)
                        {
                            if (SUCCEEDED(pIShellFolderDesktop->BindToObject(pidlParent, NULL, __uuidof (pIShellFolder), (void**)&pIShellFolder)))
                            {
                                if (pIShellFolder != NULL)
                                {
                                    if (SUCCEEDED(pIShellFolder->QueryInterface(riid, ppv)))
                                    {
                                        if (ppidlLast)
                                        {
                                            *ppidlLast = CopyPIDL((LPCITEMIDLIST)pRel);
                                            bRet = TRUE;
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        if (pidlParent != NULL)
        {
            free(pidlParent);
            pidlParent = NULL;
        }
        if (pIShellFolder != NULL)
        {
            pIShellFolder->Release();
            pIShellFolder = NULL;
        }
        if (pIShellFolderDesktop != NULL)
        {
            pIShellFolderDesktop->Release();
            pIShellFolderDesktop = NULL;
        }
        return bRet;
    }
    static LRESULT CALLBACK HookWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
        LRESULT lResult = 0;
        IContextMenu2* pIContextMenu2 = CShellContextMenu::IContext2();
        IContextMenu3* pIContextMenu3 = CShellContextMenu::IContext3();
        switch (message)
        {
        case WM_MENUCHAR:   // only supported by IContextMenu3
            if (pIContextMenu3 != NULL)
            {
                pIContextMenu3->HandleMenuMsg2(message, wParam, lParam, &lResult);
                return (lResult);
            }
            break;
        case WM_DRAWITEM:
        case WM_MEASUREITEM:
            if (wParam)
            {
                break; // if wParam != 0 then the message is not menu-related
            }
        case WM_INITMENUPOPUP:
            if (pIContextMenu2)
            {
                pIContextMenu2->HandleMenuMsg(message, wParam, lParam);
            }
            else    // version 3
            {
                pIContextMenu3->HandleMenuMsg(message, wParam, lParam);
            }
            return (message == WM_INITMENUPOPUP ? 0 : TRUE); // inform caller that we handled WM_INITPOPUPMENU by ourself
            break;
        default:
            break;
        }
        // call original WndProc of window to prevent undefined bevhaviour of window
        return ::CallWindowProcW((WNDPROC)GetPropW(hWnd, (L"OldWndProc")), hWnd, message, wParam, lParam);
    }
    VOID FreePIDLArray(LPITEMIDLIST* pidlArray)
    {
        if (pidlArray != NULL)
        {
            int iSize = (int)_msize(pidlArray) / sizeof(LPITEMIDLIST);
            for (int i = 0; i < iSize; i++)
            {
                free(pidlArray[i]);
                pidlArray[i] = NULL;
            }
            free(pidlArray);
            pidlArray = NULL;
        }
    }
    LPITEMIDLIST CopyPIDL(LPCITEMIDLIST pidl, int cb = (-1))
    {
        if (cb == -1)
        {
            cb = GetPIDLSize(pidl); // Calculate size of list.
        }
        LPITEMIDLIST pidlRet = (LPITEMIDLIST)calloc(cb + sizeof(USHORT), sizeof(BYTE));
        if (pidlRet)
        {
            CopyMemory(pidlRet, pidl, cb);
        }
        return (pidlRet);
    }
    UINT GetPIDLSize(LPCITEMIDLIST pidl)
    {
        if (!pidl)
        {
            return 0;
        }
        int nSize = 0;
        LPITEMIDLIST pidlTemp = (LPITEMIDLIST)pidl;
        while (pidlTemp->mkid.cb)
        {
            nSize += pidlTemp->mkid.cb;
            pidlTemp = (LPITEMIDLIST)(((LPBYTE)pidlTemp) + pidlTemp->mkid.cb);
        }
        return nSize;
    }
    LPBYTE GetPIDLPos(LPCITEMIDLIST pidl, int nPos)
    {
        if (!pidl)
        {
            return 0;
        }
        int nCount = 0;
        BYTE* pCur = (BYTE*)pidl;
        while (((LPCITEMIDLIST)pCur)->mkid.cb)
        {
            if (nCount == nPos)
            {
                return pCur;
            }
            nCount++;
            pCur += ((LPCITEMIDLIST)pCur)->mkid.cb;    // + sizeof(pidl->mkid.cb);
        }
        if (nCount == nPos)
        {
            return pCur;
        }
        return NULL;
    }
    int GetPIDLCount(LPCITEMIDLIST pidl)
    {
        if (!pidl)
        {
            return 0;
        }
        int nCount = 0;
        BYTE* pCur = (BYTE*)pidl;
        while (((LPCITEMIDLIST)pCur)->mkid.cb)
        {
            nCount++;
            pCur += ((LPCITEMIDLIST)pCur)->mkid.cb;
        }
        return nCount;
    }
};

简单快捷方式:

   #define QCM_CMD_MIN 0x0001
   #define QCM_CMD_MAX 0x7FFF
   BOOL RightPathMenuByGetUIObjectOf(HWND hWnd, LPCWSTR lpPathName = (L"C:\\Users\\xxx\\Desktop"))
    {
        BOOL ret = FALSE;
        POINT pt = { 0 };
        HMENU hMenu = NULL;
        IShellView* pIShellView = NULL;
        CMINVOKECOMMANDINFOEX cmiciex = { 0 };
        ITEMIDLIST* pItemIDListDesktop = NULL;
        IShellFolder* pIShellFolderQuery = NULL;
        IShellFolder* pIShellFolderDesktop = NULL;
        static IContextMenu* G_RightPathMenuByGetUIObjectOf_pIContextMenu = NULL;
        static IContextMenu2* G_RightPathMenuByGetUIObjectOf_pIContextMenu2 = NULL;
        static IContextMenu3* G_RightPathMenuByGetUIObjectOf_pIContextMenu3 = NULL;
        static LRESULT(CALLBACK * G_RightPathMenuByGetUIObjectOf_SubClassProc)(HWND, UINT, WPARAM, LPARAM, UINT_PTR, DWORD_PTR) = []
        (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)->LRESULT CALLBACK
        {
            UNREFERENCED_PARAMETER(dwRefData);
            UNREFERENCED_PARAMETER(uIdSubclass);
            LRESULT lResult = 0;
            switch (uMsg)
            {
            case WM_MEASUREITEM:
            case WM_DRAWITEM:
            case WM_INITMENUPOPUP:
            case WM_MENUCHAR:
            {
                // wParam is 0 if this item was sent by a menu.
                if ((uMsg == WM_MEASUREITEM || uMsg == WM_DRAWITEM) && wParam != 0)
                {
                    break;
                }
                if (G_RightPathMenuByGetUIObjectOf_pIContextMenu3 != nullptr)
                {
                    if (SUCCEEDED(G_RightPathMenuByGetUIObjectOf_pIContextMenu3->HandleMenuMsg2(uMsg, wParam, lParam, &lResult)))
                    {
                        return lResult;
                    }
                }
                else if (G_RightPathMenuByGetUIObjectOf_pIContextMenu2 != NULL)
                {
                    G_RightPathMenuByGetUIObjectOf_pIContextMenu2->HandleMenuMsg(uMsg, wParam, lParam);
                }
            }
            break;
            case WM_MENUSELECT:
            {
            }
            break;
            }
            return DefSubclassProc(hWnd, uMsg, wParam, lParam);
        };
        if (SUCCEEDED(::SHGetDesktopFolder(&pIShellFolderDesktop)))
        {
            if (SUCCEEDED(pIShellFolderDesktop->ParseDisplayName(NULL, NULL, (LPWSTR)lpPathName, NULL, &pItemIDListDesktop, NULL)))
            {
                if (SUCCEEDED(pIShellFolderDesktop->GetUIObjectOf(NULL, 1, (LPCITEMIDLIST*)&pItemIDListDesktop, IID_IShellView, NULL, (void**)&pIShellView)))
                {
                    if (SUCCEEDED(pIShellView->GetItemObject(SVGIO_BACKGROUND, IID_PPV_ARGS(&G_RightPathMenuByGetUIObjectOf_pIContextMenu))))
                    {
                        SUCCEEDED(G_RightPathMenuByGetUIObjectOf_pIContextMenu->QueryInterface(IID_PPV_ARGS(&G_RightPathMenuByGetUIObjectOf_pIContextMenu3)));
                        SUCCEEDED(G_RightPathMenuByGetUIObjectOf_pIContextMenu->QueryInterface(IID_PPV_ARGS(&G_RightPathMenuByGetUIObjectOf_pIContextMenu2)));
                        if (::GetCursorPos(&pt) == TRUE)
                        {
                            hMenu = ::CreatePopupMenu();
                            if (hMenu != NULL)
                            {
                                if (G_RightPathMenuByGetUIObjectOf_pIContextMenu3 != NULL)
                                {
                                    G_RightPathMenuByGetUIObjectOf_pIContextMenu3->QueryContextMenu(hMenu, ::GetMenuItemCount(hMenu), QCM_CMD_MIN, QCM_CMD_MAX, CMF_NORMAL | CMF_SYNCCASCADEMENU | CMF_EXPLORE | CMF_EXTENDEDVERBS);
                                }
                                else
                                {
                                    if (G_RightPathMenuByGetUIObjectOf_pIContextMenu2 != NULL)
                                    {
                                        G_RightPathMenuByGetUIObjectOf_pIContextMenu2->QueryContextMenu(hMenu, ::GetMenuItemCount(hMenu), QCM_CMD_MIN, QCM_CMD_MAX, CMF_NORMAL | CMF_EXPLORE | CMF_ITEMMENU | CMF_EXTENDEDVERBS | CMF_SYNCCASCADEMENU);
                                    }
                                    else
                                    {
                                        G_RightPathMenuByGetUIObjectOf_pIContextMenu->QueryContextMenu(hMenu, ::GetMenuItemCount(hMenu), QCM_CMD_MIN, QCM_CMD_MAX, CMF_NORMAL | CMF_EXPLORE | CMF_ITEMMENU | CMF_EXTENDEDVERBS | CMF_SYNCCASCADEMENU);
                                    }
                                }
                                // Subclass the owner window, so that the shell can handle menu messages.
                                if (::SetWindowSubclass(hWnd, G_RightPathMenuByGetUIObjectOf_SubClassProc, QCM_CMD_MIN, (DWORD_PTR)(NULL)) == TRUE)
                                {
                                    ret = ::TrackPopupMenu(hMenu, TPM_RETURNCMD | TPM_LEFTALIGN, pt.x, pt.y, 0, hWnd, NULL);
                                    // Restore previous window procedure.
                                    ::RemoveWindowSubclass(hWnd, G_RightPathMenuByGetUIObjectOf_SubClassProc, QCM_CMD_MIN);
                                    cmiciex.cbSize = sizeof(CMINVOKECOMMANDINFOEX);
                                    cmiciex.fMask = CMIC_MASK_UNICODE | CMIC_MASK_PTINVOKE;
                                    cmiciex.nShow = SW_SHOWNORMAL;
                                    cmiciex.hwnd = hWnd;
                                    cmiciex.ptInvoke = pt;
                                    cmiciex.lpDirectoryW = lpPathName;
                                    cmiciex.lpVerb = (LPSTR)MAKEINTRESOURCEA(ret - QCM_CMD_MIN);
                                    cmiciex.lpVerbW = (LPWSTR)MAKEINTRESOURCEW(ret - QCM_CMD_MIN);
                                    if (G_RightPathMenuByGetUIObjectOf_pIContextMenu3 != NULL)
                                    {
                                        SUCCEEDED(G_RightPathMenuByGetUIObjectOf_pIContextMenu3->InvokeCommand((CMINVOKECOMMANDINFO*)&cmiciex));
                                    }
                                    else
                                    {
                                        if (G_RightPathMenuByGetUIObjectOf_pIContextMenu2 != NULL)
                                        {
                                            SUCCEEDED(G_RightPathMenuByGetUIObjectOf_pIContextMenu2->InvokeCommand((CMINVOKECOMMANDINFO*)&cmiciex));
                                        }
                                        else
                                        {
                                            SUCCEEDED(G_RightPathMenuByGetUIObjectOf_pIContextMenu->InvokeCommand((CMINVOKECOMMANDINFO*)&cmiciex));
                                        }
                                    }
                                }
                            }
                        }
                        if (G_RightPathMenuByGetUIObjectOf_pIContextMenu3 != NULL)
                        {
                            G_RightPathMenuByGetUIObjectOf_pIContextMenu3->Release();
                            G_RightPathMenuByGetUIObjectOf_pIContextMenu3 = NULL;
                        }
                        if (G_RightPathMenuByGetUIObjectOf_pIContextMenu2 != NULL)
                        {
                            G_RightPathMenuByGetUIObjectOf_pIContextMenu2->Release();
                            G_RightPathMenuByGetUIObjectOf_pIContextMenu2 = NULL;
                        }
                        G_RightPathMenuByGetUIObjectOf_pIContextMenu->Release();
                        G_RightPathMenuByGetUIObjectOf_pIContextMenu = NULL;
                    }
                    pIShellView->Release();
                    pIShellView = NULL;
                }
                ::ILFree(pItemIDListDesktop);
                pItemIDListDesktop = NULL;
            }
            pIShellFolderDesktop->Release();
            pIShellFolderDesktop = NULL;
        }
        return ret;
    }
    BOOL RightPathMenuByBindToObjectAndCreateViewObject(HWND hWnd, LPCWSTR lpPathName = (L"C:\\Users\\xxx\\Desktop"))
    {
        BOOL ret = FALSE;
        POINT pt = { 0 };
        HMENU hMenu = NULL;
        IShellView* pIShellView = NULL;
        CMINVOKECOMMANDINFOEX cmiciex = { 0 };
        ITEMIDLIST* pItemIDListDesktop = NULL;
        IShellFolder* pIShellFolderQuery = NULL;
        IShellFolder* pIShellFolderDesktop = NULL;
        static IContextMenu* G_RightPathMenuByBindToObjectAndCreateViewObject_pIContextMenu = NULL;
        static IContextMenu2* G_RightPathMenuByBindToObjectAndCreateViewObject_pIContextMenu2 = NULL;
        static IContextMenu3* G_RightPathMenuByBindToObjectAndCreateViewObject_pIContextMenu3 = NULL;
        static LRESULT(CALLBACK * G_RightPathMenuByBindToObjectAndCreateViewObject_SubClassProc)(HWND, UINT, WPARAM, LPARAM, UINT_PTR, DWORD_PTR) = []
            (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)->LRESULT CALLBACK
        {
            UNREFERENCED_PARAMETER(dwRefData);
            UNREFERENCED_PARAMETER(uIdSubclass);
            LRESULT lResult = 0;
            switch (uMsg)
            {
            case WM_MEASUREITEM:
            case WM_DRAWITEM:
            case WM_INITMENUPOPUP:
            case WM_MENUCHAR:
            {
                // wParam is 0 if this item was sent by a menu.
                if ((uMsg == WM_MEASUREITEM || uMsg == WM_DRAWITEM) && wParam != 0)
                {
                    break;
                }
                if (G_RightPathMenuByBindToObjectAndCreateViewObject_pIContextMenu3 != nullptr)
                {
                    if (SUCCEEDED(G_RightPathMenuByBindToObjectAndCreateViewObject_pIContextMenu3->HandleMenuMsg2(uMsg, wParam, lParam, &lResult)))
                    {
                        return lResult;
                    }
                }
                else if (G_RightPathMenuByBindToObjectAndCreateViewObject_pIContextMenu2 != NULL)
                {
                    G_RightPathMenuByBindToObjectAndCreateViewObject_pIContextMenu2->HandleMenuMsg(uMsg, wParam, lParam);
                }
            }
            break;
            case WM_MENUSELECT:
            {
            }
            break;
            }
            return DefSubclassProc(hWnd, uMsg, wParam, lParam);
        };
        if (SUCCEEDED(::SHGetDesktopFolder(&pIShellFolderDesktop)))
        {
            if (SUCCEEDED(pIShellFolderDesktop->ParseDisplayName(NULL, NULL, (LPWSTR)lpPathName, NULL, &pItemIDListDesktop, NULL)))
            {
                if (SUCCEEDED(pIShellFolderDesktop->BindToObject(pItemIDListDesktop, NULL, IID_PPV_ARGS(&pIShellFolderQuery))))
                {
                    if (SUCCEEDED(pIShellFolderQuery->CreateViewObject(NULL, IID_PPV_ARGS(&pIShellView))))
                    {
                        if (SUCCEEDED(pIShellView->GetItemObject(SVGIO_BACKGROUND, IID_PPV_ARGS(&G_RightPathMenuByBindToObjectAndCreateViewObject_pIContextMenu))))
                        {
                            SUCCEEDED(G_RightPathMenuByBindToObjectAndCreateViewObject_pIContextMenu->QueryInterface(IID_PPV_ARGS(&G_RightPathMenuByBindToObjectAndCreateViewObject_pIContextMenu3)));
                            SUCCEEDED(G_RightPathMenuByBindToObjectAndCreateViewObject_pIContextMenu->QueryInterface(IID_PPV_ARGS(&G_RightPathMenuByBindToObjectAndCreateViewObject_pIContextMenu2)));
                            if (::GetCursorPos(&pt) == TRUE)
                            {
                                hMenu = ::CreatePopupMenu();
                                if (hMenu != NULL)
                                {
                                    if (G_RightPathMenuByBindToObjectAndCreateViewObject_pIContextMenu3 != NULL)
                                    {
                                        G_RightPathMenuByBindToObjectAndCreateViewObject_pIContextMenu3->QueryContextMenu(hMenu, ::GetMenuItemCount(hMenu), QCM_CMD_MIN, QCM_CMD_MAX, CMF_NORMAL | CMF_SYNCCASCADEMENU | CMF_EXPLORE | CMF_EXTENDEDVERBS);
                                    }
                                    else
                                    {
                                        if (G_RightPathMenuByBindToObjectAndCreateViewObject_pIContextMenu2 != NULL)
                                        {
                                            G_RightPathMenuByBindToObjectAndCreateViewObject_pIContextMenu2->QueryContextMenu(hMenu, ::GetMenuItemCount(hMenu), QCM_CMD_MIN, QCM_CMD_MAX, CMF_NORMAL | CMF_EXPLORE | CMF_ITEMMENU | CMF_EXTENDEDVERBS | CMF_SYNCCASCADEMENU);
                                        }
                                        else
                                        {
                                            G_RightPathMenuByBindToObjectAndCreateViewObject_pIContextMenu->QueryContextMenu(hMenu, ::GetMenuItemCount(hMenu), QCM_CMD_MIN, QCM_CMD_MAX, CMF_NORMAL | CMF_EXPLORE | CMF_ITEMMENU | CMF_EXTENDEDVERBS | CMF_SYNCCASCADEMENU);
                                        }
                                    }
                                    // Subclass the owner window, so that the shell can handle menu messages.
                                    if (::SetWindowSubclass(hWnd, G_RightPathMenuByBindToObjectAndCreateViewObject_SubClassProc, QCM_CMD_MIN, (DWORD_PTR)(NULL)) == TRUE)
                                    {
                                        ret = ::TrackPopupMenu(hMenu, TPM_RETURNCMD | TPM_LEFTALIGN, pt.x, pt.y, 0, hWnd, NULL);
                                        // Restore previous window procedure.
                                        ::RemoveWindowSubclass(hWnd, G_RightPathMenuByBindToObjectAndCreateViewObject_SubClassProc, QCM_CMD_MIN);
                                        cmiciex.cbSize = sizeof(CMINVOKECOMMANDINFOEX);
                                        cmiciex.fMask = CMIC_MASK_UNICODE | CMIC_MASK_PTINVOKE;
                                        cmiciex.nShow = SW_SHOWNORMAL;
                                        cmiciex.hwnd = hWnd;
                                        cmiciex.ptInvoke = pt;
                                        cmiciex.lpDirectoryW = lpPathName;
                                        cmiciex.lpVerb = (LPSTR)MAKEINTRESOURCEA(ret - QCM_CMD_MIN);
                                        cmiciex.lpVerbW = (LPWSTR)MAKEINTRESOURCEW(ret - QCM_CMD_MIN);
                                        if (G_RightPathMenuByBindToObjectAndCreateViewObject_pIContextMenu3 != NULL)
                                        {
                                            SUCCEEDED(G_RightPathMenuByBindToObjectAndCreateViewObject_pIContextMenu3->InvokeCommand((CMINVOKECOMMANDINFO*)&cmiciex));
                                        }
                                        else
                                        {
                                            if (G_RightPathMenuByBindToObjectAndCreateViewObject_pIContextMenu2 != NULL)
                                            {
                                                SUCCEEDED(G_RightPathMenuByBindToObjectAndCreateViewObject_pIContextMenu2->InvokeCommand((CMINVOKECOMMANDINFO*)&cmiciex));
                                            }
                                            else
                                            {
                                                SUCCEEDED(G_RightPathMenuByBindToObjectAndCreateViewObject_pIContextMenu->InvokeCommand((CMINVOKECOMMANDINFO*)&cmiciex));
                                            }
                                        }
                                    }
                                }
                            }
                            if (G_RightPathMenuByBindToObjectAndCreateViewObject_pIContextMenu3 != NULL)
                            {
                                G_RightPathMenuByBindToObjectAndCreateViewObject_pIContextMenu3->Release();
                                G_RightPathMenuByBindToObjectAndCreateViewObject_pIContextMenu3 = NULL;
                            }
                            if (G_RightPathMenuByBindToObjectAndCreateViewObject_pIContextMenu2 != NULL)
                            {
                                G_RightPathMenuByBindToObjectAndCreateViewObject_pIContextMenu2->Release();
                                G_RightPathMenuByBindToObjectAndCreateViewObject_pIContextMenu2 = NULL;
                            }
                            G_RightPathMenuByBindToObjectAndCreateViewObject_pIContextMenu->Release();
                            G_RightPathMenuByBindToObjectAndCreateViewObject_pIContextMenu = NULL;
                        }
                        pIShellView->Release();
                        pIShellView = NULL;
                    }
                    pIShellFolderQuery->Release();
                    pIShellFolderQuery = NULL;
                }
                ::ILFree(pItemIDListDesktop);
                pItemIDListDesktop = NULL;
            }
            pIShellFolderDesktop->Release();
            pIShellFolderDesktop = NULL;
        }
        return ret;
    }
    BOOL RightFileMenuByGetUIObjectOf(HWND hWnd, LPCWSTR lpFileName = (L"C:\\Users\\xxx\\Desktop"))
    {
        BOOL ret = FALSE;
        POINT pt = { 0 };
        HMENU hMenu = NULL;
        IShellView* pIShellView = NULL;
        IContextMenu* pIContextMenu = NULL;
        CMINVOKECOMMANDINFOEX cmiciex = { 0 };
        IContextMenu2* pIContextMenu2 = NULL;
        IContextMenu3* pIContextMenu3 = NULL;
        ITEMIDLIST* pItemIDListPathName = NULL;
        IShellFolder* pIShellFolderBind = NULL;
        IShellFolder* pIShellFolderQuery = NULL;
        IShellFolder* pIShellFolderDesktop = NULL;
        ITEMIDLIST* pItemIDListPathNameFull = NULL;
        ITEMIDLIST* pItemIDListPathNameLast = NULL;
        static IContextMenu* G_RightFileMenuByGetUIObjectOf_pIContextMenu = NULL;
        static IContextMenu2* G_RightFileMenuByGetUIObjectOf_pIContextMenu2 = NULL;
        static IContextMenu3* G_RightFileMenuByGetUIObjectOf_pIContextMenu3 = NULL;
        static LRESULT(CALLBACK * G_RightFileMenuByGetUIObjectOf_SubClassProc)(HWND, UINT, WPARAM, LPARAM, UINT_PTR, DWORD_PTR) = []
        (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)->LRESULT CALLBACK
        {
            UNREFERENCED_PARAMETER(dwRefData);
            UNREFERENCED_PARAMETER(uIdSubclass);
            LRESULT lResult = 0;
            switch (uMsg)
            {
            case WM_MEASUREITEM:
            case WM_DRAWITEM:
            case WM_INITMENUPOPUP:
            case WM_MENUCHAR:
            {
                // wParam is 0 if this item was sent by a menu.
                if ((uMsg == WM_MEASUREITEM || uMsg == WM_DRAWITEM) && wParam != 0)
                {
                    break;
                }
                if (G_RightFileMenuByGetUIObjectOf_pIContextMenu3 != nullptr)
                {
                    if (SUCCEEDED(G_RightFileMenuByGetUIObjectOf_pIContextMenu3->HandleMenuMsg2(uMsg, wParam, lParam, &lResult)))
                    {
                        return lResult;
                    }
                }
                else if (G_RightFileMenuByGetUIObjectOf_pIContextMenu2 != NULL)
                {
                    G_RightFileMenuByGetUIObjectOf_pIContextMenu2->HandleMenuMsg(uMsg, wParam, lParam);
                }
            }
            break;
            case WM_MENUSELECT:
            {
            }
            break;
            }
            return DefSubclassProc(hWnd, uMsg, wParam, lParam);
        };
        if (SUCCEEDED(::SHGetDesktopFolder(&pIShellFolderDesktop)))
        {
            if (SUCCEEDED(pIShellFolderDesktop->ParseDisplayName(NULL, NULL, (LPWSTR)lpFileName, NULL, &pItemIDListPathName, NULL)))
            {
                UINT nItemIDListSize = ::ILGetSize(pItemIDListPathName);
                if (nItemIDListSize > 0)
                {
                    if (nItemIDListSize == pItemIDListPathName->mkid.cb)
                    {
                        if (SUCCEEDED(pIShellFolderDesktop->QueryInterface(IID_PPV_ARGS(&pIShellFolderQuery))))
                        {
                            pItemIDListPathNameLast = ::ILCloneFirst(pItemIDListPathName);
                        }
                    }
                    else
                    {
                        pItemIDListPathNameFull = ILCloneFull(pItemIDListPathName);
                        if (pItemIDListPathNameFull != NULL)
                        {
                            if (::ILRemoveLastID(pItemIDListPathNameFull) == TRUE)
                            {
                                if (SUCCEEDED(pIShellFolderDesktop->BindToObject(pItemIDListPathNameFull, NULL, IID_PPV_ARGS(&pIShellFolderBind))))
                                {
                                    if (SUCCEEDED(pIShellFolderBind->QueryInterface(IID_PPV_ARGS(&pIShellFolderQuery))))
                                    {
                                        pItemIDListPathNameLast = ::ILClone(::ILFindLastID(pItemIDListPathName));
                                    }
                                    pIShellFolderBind->Release();
                                    pIShellFolderBind = NULL;
                                }
                            }
                            ::ILFree(pItemIDListPathNameFull);
                            pItemIDListPathNameFull = NULL;
                        }
                    }
                    if (pItemIDListPathNameLast != NULL)
                    {
                        if (pIShellFolderQuery != NULL)
                        {
                            if (SUCCEEDED(pIShellFolderQuery->GetUIObjectOf(NULL, 1, (LPCITEMIDLIST*)&pItemIDListPathNameLast, IID_IContextMenu, NULL, (void**)&G_RightFileMenuByGetUIObjectOf_pIContextMenu)))
                            {
                                SUCCEEDED(G_RightFileMenuByGetUIObjectOf_pIContextMenu->QueryInterface(IID_PPV_ARGS(&G_RightFileMenuByGetUIObjectOf_pIContextMenu3)));
                                SUCCEEDED(G_RightFileMenuByGetUIObjectOf_pIContextMenu->QueryInterface(IID_PPV_ARGS(&G_RightFileMenuByGetUIObjectOf_pIContextMenu2)));
                                if (::GetCursorPos(&pt) == TRUE)
                                {
                                    hMenu = ::CreatePopupMenu();
                                    if (hMenu != NULL)
                                    {
                                        if (G_RightFileMenuByGetUIObjectOf_pIContextMenu3 != NULL)
                                        {
                                            G_RightFileMenuByGetUIObjectOf_pIContextMenu3->QueryContextMenu(hMenu, ::GetMenuItemCount(hMenu), QCM_CMD_MIN, QCM_CMD_MAX, CMF_NORMAL | CMF_EXPLORE | CMF_CANRENAME);
                                
                                        }
                                        else
                                        {
                                            if (G_RightFileMenuByGetUIObjectOf_pIContextMenu2 != NULL)
                                            {
                                                G_RightFileMenuByGetUIObjectOf_pIContextMenu2->QueryContextMenu(hMenu, ::GetMenuItemCount(hMenu), QCM_CMD_MIN, QCM_CMD_MAX, CMF_NORMAL | CMF_EXPLORE | CMF_CANRENAME);
                                            }
                                            else
                                            {
                                                G_RightFileMenuByGetUIObjectOf_pIContextMenu->QueryContextMenu(hMenu, ::GetMenuItemCount(hMenu), QCM_CMD_MIN, QCM_CMD_MAX, CMF_NORMAL | CMF_EXPLORE | CMF_CANRENAME);
                                            }
                                        }
                                        // Subclass the owner window, so that the shell can handle menu messages.
                                        if (::SetWindowSubclass(hWnd, G_RightFileMenuByGetUIObjectOf_SubClassProc, QCM_CMD_MIN, (DWORD_PTR)(NULL)) == TRUE)
                                        {
                                            ret = ::TrackPopupMenu(hMenu, TPM_RETURNCMD | TPM_LEFTALIGN, pt.x, pt.y, 0, hWnd, NULL);
                                            // Restore previous window procedure.
                                            ::RemoveWindowSubclass(hWnd, G_RightFileMenuByGetUIObjectOf_SubClassProc, QCM_CMD_MIN);
                                            cmiciex.cbSize = sizeof(CMINVOKECOMMANDINFOEX);
                                            cmiciex.fMask = CMIC_MASK_UNICODE | CMIC_MASK_PTINVOKE;
                                            cmiciex.nShow = SW_SHOWNORMAL;
                                            cmiciex.hwnd = hWnd;
                                            cmiciex.ptInvoke = pt;
                                            cmiciex.lpVerb = (LPSTR)MAKEINTRESOURCEA(ret - QCM_CMD_MIN);
                                            cmiciex.lpVerbW = (LPWSTR)MAKEINTRESOURCEW(ret - QCM_CMD_MIN);
                                            if (G_RightFileMenuByGetUIObjectOf_pIContextMenu3 != NULL)
                                            {
                                                SUCCEEDED(G_RightFileMenuByGetUIObjectOf_pIContextMenu3->InvokeCommand((CMINVOKECOMMANDINFO*)&cmiciex));
                                            }
                                            else
                                            {
                                                if (G_RightFileMenuByGetUIObjectOf_pIContextMenu2 != NULL)
                                                {
                                                    SUCCEEDED(G_RightFileMenuByGetUIObjectOf_pIContextMenu3->InvokeCommand((CMINVOKECOMMANDINFO*)&cmiciex));
                                                }
                                                else
                                                {
                                                    SUCCEEDED(G_RightFileMenuByGetUIObjectOf_pIContextMenu3->InvokeCommand((CMINVOKECOMMANDINFO*)&cmiciex));
                                                }
                                            }
                                        }
                                    }
                                }
                                if (G_RightFileMenuByGetUIObjectOf_pIContextMenu3 != NULL)
                                {
                                    G_RightFileMenuByGetUIObjectOf_pIContextMenu3->Release();
                                    G_RightFileMenuByGetUIObjectOf_pIContextMenu3 = NULL;
                                }
                                if (G_RightFileMenuByGetUIObjectOf_pIContextMenu2 != NULL)
                                {
                                    G_RightFileMenuByGetUIObjectOf_pIContextMenu2->Release();
                                    G_RightFileMenuByGetUIObjectOf_pIContextMenu2 = NULL;
                                }
                                G_RightFileMenuByGetUIObjectOf_pIContextMenu->Release();
                                G_RightFileMenuByGetUIObjectOf_pIContextMenu = NULL;
                            }
                            pIShellFolderQuery->Release();
                            pIShellFolderQuery = NULL;
                        }
                        ::ILFree(pItemIDListPathNameLast);
                        pItemIDListPathNameLast = NULL;
                    }
                }
                ::ILFree(pItemIDListPathName);
                pItemIDListPathName = NULL;
            }
            pIShellFolderDesktop->Release();
            pIShellFolderDesktop = NULL;
        }
        return ret;
    }


×
打赏作者
最新回复 (0)
只看楼主
全部楼主
返回