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)
X
正在加载信息~
2
最新回复 (0)