void CShellContextMenu::SetObjects(const QStringList &strList) { // free all allocated datas if (m_psfFolder && bDelete) m_psfFolder->Release (); m_psfFolder = NULL; FreePIDLArray (m_pidlArray); m_pidlArray = NULL; // get IShellFolder interface of Desktop (root of shell namespace) IShellFolder * psfDesktop = NULL; SHGetDesktopFolder (&psfDesktop); // needed to obtain full qualified pidl // 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 LPITEMIDLIST pidl = NULL; psfDesktop->ParseDisplayName (NULL, 0, (LPOLESTR)strList[0].utf16(), NULL, &pidl, NULL); // now we need the parent IShellFolder interface of pidl, and the relative PIDL to that interface LPITEMIDLIST pidlItem = NULL; // relative pidl SHBindToParentEx (pidl, IID_IShellFolder, (void **) &m_psfFolder, NULL); free (pidlItem); // get interface to IMalloc (need to free the PIDLs allocated by the shell functions) LPMALLOC lpMalloc = NULL; SHGetMalloc (&lpMalloc); lpMalloc->Free (pidl); // 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 IShellFolder * psfFolder = NULL; nItems = strList.size (); for (int i = 0; i < nItems; i++) { pidl=0; psfDesktop->ParseDisplayName (NULL, 0, (LPOLESTR)strList[i].utf16(), NULL, &pidl, NULL); if (pidl) { m_pidlArray = (LPITEMIDLIST *) realloc (m_pidlArray, (i + 1) * sizeof (LPITEMIDLIST)); // get relative pidl via SHBindToParent SHBindToParentEx (pidl, IID_IShellFolder, (void **) &psfFolder, (LPCITEMIDLIST *) &pidlItem); m_pidlArray[i] = CopyPIDL (pidlItem); // copy relative pidl to pidlArray free (pidlItem); lpMalloc->Free (pidl); // free pidl allocated by ParseDisplayName psfFolder->Release (); } } lpMalloc->Release (); psfDesktop->Release (); bDelete = TRUE; // indicates that m_psfFolder should be deleted by CShellContextMenu }
HRESULT CContextMenuHelper::SHGetContextMenu(std::vector<LPCTSTR> files) { HRESULT hr; IMalloc *pm = NULL; IShellFolder *pDesktop = NULL; IShellFolder *psf = NULL; LPITEMIDLIST pidl = NULL; WCHAR fwname[MAX_PATH + 1]; if (SUCCEEDED(hr = SHGetMalloc(&pm))) { if (SUCCEEDED(hr = SHGetDesktopFolder(&pDesktop))) { std::vector<LPITEMIDLIST> pidls; IShellFolder* psfFolder = NULL; for (UINT i = 0; SUCCEEDED(hr) && i < files.size(); i++) { LPCTSTR lpszFilePath = files[i]; ULONG cch; ULONG attrs; // Convert to Unicode memset(fwname, L'\0', (MAX_PATH + 1) * sizeof(WCHAR)); MultiByteToWideChar(CP_THREAD_ACP, 0, lpszFilePath, -1, fwname, MAX_PATH); if (SUCCEEDED(hr = pDesktop->ParseDisplayName(m_hWnd, NULL, fwname, &cch, &pidl, &attrs))) { LPITEMIDLIST pidlItem = NULL; if (SUCCEEDED(hr = SHBindToParentEx((LPCITEMIDLIST)pidl, IID_IShellFolder, (void **)&psf, (LPCITEMIDLIST *) &pidlItem, pDesktop, pm))) { pidls.push_back(CopyPIDL(pidlItem, pm)); pm->Free(pidlItem); if (psfFolder == NULL) { // Remember first folder and we wiil show menu for this one // All other folder will be ignored psfFolder = psf; } else { psf->Release(); } } pm->Free(pidl); } } if (SUCCEEDED(hr) && psfFolder != NULL) { hr = psfFolder->GetUIObjectOf(m_hWnd, pidls.size(), const_cast<LPCITEMIDLIST*>(pidls.begin()), IID_IContextMenu, NULL, (void**)&m_lpcm); psfFolder->Release(); } FreeItemIDList(pidls, pm); pDesktop->Release(); } pm->Release(); } return hr; }
void CShellContextMenu::SetObjects(CString &strArray) { // free all allocated datas if (m_psfFolder && bDelete) m_psfFolder->Release (); m_psfFolder = NULL; FreePIDLArray (m_pidlArray); m_pidlArray = NULL; // get IShellFolder interface of Desktop (root of shell namespace) IShellFolder * psfDesktop = NULL; SHGetDesktopFolder (&psfDesktop); // needed to obtain full qualified pidl // 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 LPITEMIDLIST pidl = NULL; #ifndef _UNICODE OLECHAR * olePath = (OLECHAR *) calloc (strArray.GetLength () + 1, sizeof (OLECHAR)); MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, (LPCSTR)strArray, -1, olePath, strArray.GetLength () + 1); psfDesktop->ParseDisplayName (NULL, 0, olePath, NULL, &pidl, NULL); free (olePath); #else psfDesktop->ParseDisplayName (NULL, 0, strArray.GetBuffer (0), NULL, &pidl, NULL); #endif // now we need the parent IShellFolder interface of pidl, and the relative PIDL to that interface LPITEMIDLIST pidlItem = NULL; // relative pidl SHBindToParentEx (pidl, IID_IShellFolder, (void **) &m_psfFolder, NULL); free (pidlItem); // get interface to IMalloc (need to free the PIDLs allocated by the shell functions) LPMALLOC lpMalloc = NULL; SHGetMalloc (&lpMalloc); lpMalloc->Free (pidl); // 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 IShellFolder * psfFolder = NULL; nItems = 1; for (int i = 0; i < nItems; i++) { #ifndef _UNICODE olePath = (OLECHAR *) calloc (strArray.GetLength () + 1, sizeof (OLECHAR)); MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, (strArray), -1, olePath, strArray.GetLength () + 1); psfDesktop->ParseDisplayName (NULL, 0, olePath, NULL, &pidl, NULL); free (olePath); #else psfDesktop->ParseDisplayName (NULL, 0, strArray.GetBuffer (0), NULL, &pidl, NULL); #endif m_pidlArray = (LPITEMIDLIST *) realloc (m_pidlArray, (i + 1) * sizeof (LPITEMIDLIST)); // get relative pidl via SHBindToParent SHBindToParentEx (pidl, IID_IShellFolder, (void **) &psfFolder, (LPCITEMIDLIST *) &pidlItem); m_pidlArray[i] = CopyPIDL (pidlItem); // copy relative pidl to pidlArray free (pidlItem); lpMalloc->Free (pidl); // free pidl allocated by ParseDisplayName psfFolder->Release (); } lpMalloc->Release (); psfDesktop->Release (); bDelete = TRUE; // indicates that m_psfFolder should be deleted by CShellContextMenu }