// Function for obtaining an interface pointer to a COM shell object // // paths: absolute paths to the files/folders comprising the object // riid: the interface to return, eg. IID_IDropSource // pObject: the address to receive the interface pointer, caller must Release() bool UIObjectFromPaths (std::vector paths, const GUID riid, void** pObject) { if (paths.empty()) return false; // test for naked drive wchar_t buf [MAX_PATH]; bool drive = false; wcscpy (buf, paths[0].c_str()); if (buf [wcslen (buf) - 1] == L':') { drive = true; wcscat (buf, L"\\"); } else if (buf [wcslen (buf) - 2] == L':') drive = true; // test for files with single parent folder bool singledir = false; if (!drive) { wchar_t* slash = wcsrchr (buf, L'\\'); if (slash) *slash = L'\0'; singledir = true; wchar_t dir [MAX_PATH]; for (UINT i = 0; i < paths.size(); ++i) { wcscpy (dir, paths[i].c_str()); slash = wcsrchr (dir, L'\\'); if (slash) *slash = L'\0'; if (wcscmp (dir, buf) != 0) { singledir = false; break; } } } // the COM part HRESULT hr = 0; IMalloc* pMalloc = 0; hr = ::SHGetMalloc (&pMalloc); if (hr != NOERROR) return false; IShellFolder* psfDesktop = 0; hr = ::SHGetDesktopFolder(&psfDesktop); if (hr != NOERROR) { pMalloc->Release(); return false; } IShellFolder* psfFolder = 0; if (singledir) { // naked drive must have trailing backslash if (buf [wcslen (buf) - 1] == L':') wcscat (buf, L"\\"); ITEMIDLIST* pidldir = 0; ULONG chEaten = 0; ULONG attributes = 0; hr = psfDesktop->ParseDisplayName (NULL, NULL, buf, &chEaten, &pidldir, &attributes); if (hr != NOERROR) { psfDesktop->Release(); pMalloc->Release (); return false; } hr = psfDesktop->BindToObject (pidldir, NULL, IID_IShellFolder, (void**)&psfFolder); pMalloc->Free (pidldir); psfDesktop->Release(); psfDesktop = 0; if (hr != NOERROR) { pMalloc->Release (); return false; } } // build pidl[] ITEMIDLIST* pidl [paths.size()]; ULONG chEaten = 0; ULONG attributes = 0; for (UINT i = 0; i < paths.size(); ++i) { wcscpy (buf, paths[i].c_str()); if (singledir) { wchar_t* name = wcsrchr (buf, L'\\'); // name[1] ok if not drive hr = psfFolder->ParseDisplayName (NULL, NULL, &name[1], &chEaten, &pidl [i], &attributes); } else { if (buf [wcslen (buf) - 1] == L':') wcscat (buf, L"\\"); hr = psfDesktop->ParseDisplayName (NULL, NULL, buf, &chEaten, &pidl [i], &attributes); } if (hr != NOERROR) { for (UINT j = 0; j < i; ++j) // free pidls assigned so far pMalloc->Free (pidl[j]); if (psfDesktop) psfDesktop->Release(); if (psfFolder) psfFolder->Release(); pMalloc->Release (); return false; } } // get the object - for a single IShellFolder* (shellfolder interface) *pObject = NULL; if (singledir) hr = psfFolder->GetUIObjectOf (NULL, paths.size(), (LPCITEMIDLIST*)pidl, riid, NULL, pObject); else hr = psfDesktop->GetUIObjectOf (NULL, paths.size(), (LPCITEMIDLIST*)pidl, riid, NULL, pObject); // cleanup for (UINT i = 0; i < paths.size(); ++i) pMalloc->Free (pidl[i]); if (psfDesktop) psfDesktop->Release(); if (psfFolder) psfFolder->Release(); pMalloc->Release (); return SUCCEEDED(hr); }