/*********************************************************************** * SHELL32_GetDisplayNameOfChild * * Retrieves the display name of a child object of a shellfolder. * * For a pidl eg. [subpidl1][subpidl2][subpidl3]: * - it binds to the child shellfolder [subpidl1] * - asks it for the displayname of [subpidl2][subpidl3] * * Is possible the pidl is a simple pidl. In this case it asks the * subfolder for the displayname of an empty pidl. The subfolder * returns the own displayname eg. "::{guid}". This is used for * virtual folders with the registry key WantsFORPARSING set. */ HRESULT SHELL32_GetDisplayNameOfChild (IShellFolder2 * psf, LPCITEMIDLIST pidl, DWORD dwFlags, LPWSTR szOut, DWORD dwOutLen) { LPITEMIDLIST pidlFirst; HRESULT hr; TRACE ("(%p)->(pidl=%p 0x%08x %p 0x%08x)\n", psf, pidl, dwFlags, szOut, dwOutLen); pdump (pidl); pidlFirst = ILCloneFirst (pidl); if (pidlFirst) { IShellFolder2 *psfChild; hr = IShellFolder2_BindToObject (psf, pidlFirst, NULL, &IID_IShellFolder, (LPVOID *) & psfChild); if (SUCCEEDED (hr)) { STRRET strTemp; LPITEMIDLIST pidlNext = ILGetNext (pidl); hr = IShellFolder2_GetDisplayNameOf (psfChild, pidlNext, dwFlags, &strTemp); if (SUCCEEDED (hr)) { if(!StrRetToStrNW (szOut, dwOutLen, &strTemp, pidlNext)) hr = E_FAIL; } IShellFolder2_Release (psfChild); } ILFree (pidlFirst); } else hr = E_OUTOFMEMORY; TRACE ("-- ret=0x%08x %s\n", hr, debugstr_w(szOut)); return hr; }
/*********************************************************************** * SHOpenFolderAndSelectItems * * Unimplemented. */ EXTERN_C HRESULT WINAPI SHOpenFolderAndSelectItems(LPITEMIDLIST pidlFolder, UINT cidl, PCUITEMID_CHILD_ARRAY apidl, DWORD dwFlags) { ERR("SHOpenFolderAndSelectItems() is hackplemented\n"); PCIDLIST_ABSOLUTE pidlItem; if (cidl) { /* Firefox sends a full pidl here dispite the fact it is a PCUITEMID_CHILD_ARRAY -_- */ if (ILGetNext(apidl[0]) != NULL) { pidlItem = apidl[0]; } else { pidlItem = ILCombine(pidlFolder, apidl[0]); } } else { pidlItem = pidlFolder; } CComPtr<IShellFolder> psfDesktop; HRESULT hr = SHGetDesktopFolder(&psfDesktop); if (FAILED_UNEXPECTEDLY(hr)) return hr; STRRET strret; hr = psfDesktop->GetDisplayNameOf(pidlItem, SHGDN_FORPARSING, &strret); if (FAILED_UNEXPECTEDLY(hr)) return hr; WCHAR wszBuf[MAX_PATH]; hr = StrRetToBufW(&strret, pidlItem, wszBuf, _countof(wszBuf)); if (FAILED_UNEXPECTEDLY(hr)) return hr; WCHAR wszParams[MAX_PATH]; wcscpy(wszParams, L"/select,"); wcscat(wszParams, wszBuf); SHELLEXECUTEINFOW sei; memset(&sei, 0, sizeof sei); sei.cbSize = sizeof sei; sei.fMask = SEE_MASK_WAITFORINPUTIDLE; sei.lpFile = L"explorer.exe"; sei.lpParameters = wszParams; if (ShellExecuteExW(&sei)) return S_OK; else return E_FAIL; }
HRESULT SHELL32_BindToGuidItem(LPCITEMIDLIST pidlRoot, PCUIDLIST_RELATIVE pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut) { CComPtr<IPersistFolder> pFolder; HRESULT hr; if (!pidlRoot || !ppvOut || !pidl || !pidl->mkid.cb) return E_INVALIDARG; *ppvOut = NULL; GUID *pGUID = _ILGetGUIDPointer(pidl); if (!pGUID) { ERR("SHELL32_BindToGuidItem called for non guid item!\n"); return E_INVALIDARG; } hr = SHCoCreateInstance(NULL, pGUID, NULL, IID_PPV_ARG(IPersistFolder, &pFolder)); if (FAILED(hr)) return hr; if (_ILIsPidlSimple (pidl)) { hr = pFolder->Initialize(ILCombine(pidlRoot, pidl)); if (FAILED(hr)) return hr; return pFolder->QueryInterface(riid, ppvOut); } else { LPITEMIDLIST pidlChild = ILCloneFirst (pidl); if (!pidlChild) return E_OUTOFMEMORY; hr = pFolder->Initialize(ILCombine(pidlRoot, pidlChild)); ILFree(pidlChild); if (FAILED(hr)) return hr; CComPtr<IShellFolder> psf; hr = pFolder->QueryInterface(IID_PPV_ARG(IShellFolder, &psf)); if (FAILED(hr)) return hr; return psf->BindToObject(ILGetNext (pidl), pbcReserved, riid, ppvOut); } }
HRESULT SHELL32_CompareChildren(IShellFolder2* psf, LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2) { PUIDLIST_RELATIVE nextpidl1 = ILGetNext (pidl1); PUIDLIST_RELATIVE nextpidl2 = ILGetNext (pidl2); bool isEmpty1 = _ILIsDesktop(nextpidl1); bool isEmpty2 = _ILIsDesktop(nextpidl2); if (isEmpty1 || isEmpty2) return MAKE_COMPARE_HRESULT(isEmpty2 - isEmpty1); PITEMID_CHILD firstpidl = ILCloneFirst (pidl1); if (!firstpidl) return E_OUTOFMEMORY; CComPtr<IShellFolder> psf2; HRESULT hr = psf->BindToObject(firstpidl, 0, IID_PPV_ARG(IShellFolder, &psf2)); ILFree(firstpidl); if (FAILED(hr)) return MAKE_COMPARE_HRESULT(0); return psf2->CompareIDs(lParam, nextpidl1, nextpidl2); }
/*********************************************************************** * SHELL32_BindToFS [Internal] * * Common code for IShellFolder_BindToObject. * * PARAMS * pidlRoot [I] The parent shell folder's absolute pidl. * pathRoot [I] Absolute dos path of the parent shell folder. * pidlComplete [I] PIDL of the child. Relative to pidlRoot. * riid [I] GUID of the interface, which ppvOut shall be bound to. * ppvOut [O] A reference to the child's interface (riid). * * NOTES * pidlComplete has to contain at least one non empty SHITEMID. * This function makes special assumptions on the shell namespace, which * means you probably can't use it for your IShellFolder implementation. */ HRESULT SHELL32_BindToFS (LPCITEMIDLIST pidlRoot, LPCWSTR pathRoot, LPCITEMIDLIST pidlComplete, REFIID riid, LPVOID * ppvOut) { CComPtr<IShellFolder> pSF; HRESULT hr; LPCITEMIDLIST pidlChild; if (!pidlRoot || !ppvOut || !pidlComplete || !pidlComplete->mkid.cb) return E_INVALIDARG; if (_ILIsValue(pidlComplete)) { ERR("Binding to file is unimplemented\n"); return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); } if (!_ILIsFolder(pidlComplete) && !_ILIsDrive(pidlComplete)) { ERR("Got an unknown type of pidl!\n"); return E_FAIL; } *ppvOut = NULL; pidlChild = (_ILIsPidlSimple (pidlComplete)) ? pidlComplete : ILCloneFirst (pidlComplete); CLSID clsidFolder = CLSID_ShellFSFolder; DWORD attributes = _ILGetFileAttributes(ILFindLastID(pidlChild), NULL, 0); if ((attributes & (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_READONLY)) != 0) SHELL32_GetCLSIDForDirectory(pathRoot, pidlChild, &clsidFolder); hr = SHELL32_CoCreateInitSF (pidlRoot, pathRoot, pidlChild, clsidFolder, &pSF); if (pidlChild != pidlComplete) ILFree ((LPITEMIDLIST)pidlChild); if (SUCCEEDED (hr)) { if (_ILIsPidlSimple (pidlComplete)) { /* no sub folders */ hr = pSF->QueryInterface(riid, ppvOut); } else { /* go deeper */ hr = pSF->BindToObject(ILGetNext (pidlComplete), NULL, riid, ppvOut); } } TRACE ("-- returning (%p) %08x\n", *ppvOut, hr); return hr; }
/*********************************************************************** * SHELL32_GetDisplayNameOfChild * * Retrieves the display name of a child object of a shellfolder. * * For a pidl eg. [subpidl1][subpidl2][subpidl3]: * - it binds to the child shellfolder [subpidl1] * - asks it for the displayname of [subpidl2][subpidl3] * * Is possible the pidl is a simple pidl. In this case it asks the * subfolder for the displayname of an empty pidl. The subfolder * returns the own displayname eg. "::{guid}". This is used for * virtual folders with the registry key WantsFORPARSING set. */ HRESULT SHELL32_GetDisplayNameOfChild (IShellFolder2 * psf, LPCITEMIDLIST pidl, DWORD dwFlags, LPSTRRET strRet) { LPITEMIDLIST pidlFirst = ILCloneFirst(pidl); if (!pidlFirst) return E_OUTOFMEMORY; CComPtr<IShellFolder> psfChild; HRESULT hr = psf->BindToObject(pidlFirst, NULL, IID_PPV_ARG(IShellFolder, &psfChild)); if (SUCCEEDED (hr)) { hr = psfChild->GetDisplayNameOf(ILGetNext (pidl), dwFlags, strRet); } ILFree (pidlFirst); return hr; }
HRESULT SHELL32_BindToSF (LPCITEMIDLIST pidlRoot, PERSIST_FOLDER_TARGET_INFO* ppfti, LPCITEMIDLIST pidl, const GUID* clsid, REFIID riid, LPVOID *ppvOut) { PITEMID_CHILD pidlChild = ILCloneFirst (pidl); if (!pidlChild) return E_FAIL; CComPtr<IShellFolder> psf; HRESULT hr = SHELL32_CoCreateInitSF(pidlRoot, ppfti, pidlChild, clsid, IID_PPV_ARG(IShellFolder, &psf)); ILFree(pidlChild); if (FAILED_UNEXPECTEDLY(hr)) return hr; if (_ILIsPidlSimple (pidl)) return psf->QueryInterface(riid, ppvOut); else return psf->BindToObject(ILGetNext (pidl), NULL, riid, ppvOut); }
HRESULT WINAPI CRegFolder::BindToObject(PCUIDLIST_RELATIVE pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut) { CComPtr<IPersistFolder> pFolder; HRESULT hr; if (!ppvOut || !pidl || !pidl->mkid.cb) return E_INVALIDARG; *ppvOut = NULL; GUID *pGUID = _ILGetGUIDPointer(pidl); if (!pGUID) { ERR("CRegFolder::BindToObject called for non guid item!\n"); return E_INVALIDARG; } LPITEMIDLIST pidlChild = ILCloneFirst (pidl); if (!pidlChild) return E_OUTOFMEMORY; CComPtr<IShellFolder> psf; hr = SHELL32_CoCreateInitSF(m_pidlRoot, NULL, pidlChild, pGUID, -1, IID_PPV_ARG(IShellFolder, &psf)); ILFree(pidlChild); if (FAILED(hr)) return hr; if (_ILIsPidlSimple (pidl)) { return psf->QueryInterface(riid, ppvOut); } else { return psf->BindToObject(ILGetNext (pidl), pbcReserved, riid, ppvOut); } }
static BOOL BrsFolder_OnSetExpanded(browse_info *info, LPVOID selection, BOOL is_str, HTREEITEM *pItem) { LPITEMIDLIST pidlSelection = (LPITEMIDLIST)selection; LPCITEMIDLIST pidlCurrent, pidlRoot; TVITEMEXW item; BOOL bResult = FALSE; /* If 'selection' is a string, convert to a Shell ID List. */ if (is_str) { IShellFolder *psfDesktop; HRESULT hr; hr = SHGetDesktopFolder(&psfDesktop); if (FAILED(hr)) goto done; hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, (LPOLESTR)selection, NULL, &pidlSelection, NULL); IShellFolder_Release(psfDesktop); if (FAILED(hr)) goto done; } /* Move pidlCurrent behind the SHITEMIDs in pidlSelection, which are the root of * the sub-tree currently displayed. */ pidlRoot = info->lpBrowseInfo->pidlRoot; pidlCurrent = pidlSelection; while (!_ILIsEmpty(pidlRoot) && _ILIsEqualSimple(pidlRoot, pidlCurrent)) { pidlRoot = ILGetNext(pidlRoot); pidlCurrent = ILGetNext(pidlCurrent); } /* The given ID List is not part of the SHBrowseForFolder's current sub-tree. */ if (!_ILIsEmpty(pidlRoot)) goto done; /* Initialize item to point to the first child of the root folder. */ memset(&item, 0, sizeof(item)); item.mask = TVIF_PARAM; item.hItem = TreeView_GetRoot(info->hwndTreeView); if (item.hItem) item.hItem = TreeView_GetChild(info->hwndTreeView, item.hItem); /* Walk the tree along the nodes corresponding to the remaining ITEMIDLIST */ while (item.hItem && !_ILIsEmpty(pidlCurrent)) { LPTV_ITEMDATA pItemData; SendMessageW(info->hwndTreeView, TVM_GETITEMW, 0, (LPARAM)&item); pItemData = (LPTV_ITEMDATA)item.lParam; if (_ILIsEqualSimple(pItemData->lpi, pidlCurrent)) { pidlCurrent = ILGetNext(pidlCurrent); if (!_ILIsEmpty(pidlCurrent)) { /* Only expand current node and move on to it's first child, * if we didn't already reach the last SHITEMID */ SendMessageW(info->hwndTreeView, TVM_EXPAND, TVE_EXPAND, (LPARAM)item.hItem); item.hItem = TreeView_GetChild(info->hwndTreeView, item.hItem); } } else { item.hItem = TreeView_GetNextSibling(info->hwndTreeView, item.hItem); } } if (_ILIsEmpty(pidlCurrent) && item.hItem) bResult = TRUE; done: if (pidlSelection && pidlSelection != (LPITEMIDLIST)selection) ILFree(pidlSelection); if (pItem) *pItem = item.hItem; return bResult; }
/*********************************************************************** * SHELL32_CompareIDs */ HRESULT SHELL32_CompareIDs(IShellFolder2 *sf, LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2) { int type1, type2; char szTemp1[MAX_PATH]; char szTemp2[MAX_PATH]; HRESULT nReturn; LPITEMIDLIST firstpidl, nextpidl1, nextpidl2; IShellFolder *psf; /* test for empty pidls */ BOOL isEmpty1 = _ILIsDesktop (pidl1); BOOL isEmpty2 = _ILIsDesktop (pidl2); if (isEmpty1 && isEmpty2) return MAKE_HRESULT( SEVERITY_SUCCESS, 0, 0 ); if (isEmpty1) return MAKE_HRESULT( SEVERITY_SUCCESS, 0, (WORD)-1 ); if (isEmpty2) return MAKE_HRESULT( SEVERITY_SUCCESS, 0, 1 ); /* test for different types. Sort order is the PT_* constant */ type1 = _ILGetDataPointer (pidl1)->type; type2 = _ILGetDataPointer (pidl2)->type; if (type1 < type2) return MAKE_HRESULT( SEVERITY_SUCCESS, 0, (WORD)-1 ); else if (type1 > type2) return MAKE_HRESULT( SEVERITY_SUCCESS, 0, 1 ); /* test for name of pidl */ _ILSimpleGetText (pidl1, szTemp1, MAX_PATH); _ILSimpleGetText (pidl2, szTemp2, MAX_PATH); nReturn = lstrcmpiA (szTemp1, szTemp2); if (nReturn < 0) return MAKE_HRESULT( SEVERITY_SUCCESS, 0, (WORD)-1 ); else if (nReturn > 0) return MAKE_HRESULT( SEVERITY_SUCCESS, 0, 1 ); /* test of complex pidls */ firstpidl = ILCloneFirst (pidl1); nextpidl1 = ILGetNext (pidl1); nextpidl2 = ILGetNext (pidl2); /* optimizing: test special cases and bind not deeper */ /* the deeper shellfolder would do the same */ isEmpty1 = _ILIsDesktop (nextpidl1); isEmpty2 = _ILIsDesktop (nextpidl2); if (isEmpty1 && isEmpty2) { nReturn = MAKE_HRESULT( SEVERITY_SUCCESS, 0, 0 ); } else if (isEmpty1) { nReturn = MAKE_HRESULT( SEVERITY_SUCCESS, 0, (WORD)-1 ); } else if (isEmpty2) { nReturn = MAKE_HRESULT( SEVERITY_SUCCESS, 0, 1 ); /* optimizing end */ } else if (SUCCEEDED(IShellFolder2_BindToObject(sf, firstpidl, NULL, &IID_IShellFolder, (void **)&psf))) { nReturn = IShellFolder_CompareIDs (psf, lParam, nextpidl1, nextpidl2); IShellFolder_Release (psf); } ILFree (firstpidl); return nReturn; }
/*********************************************************************** * SHELL32_BindToChild [Internal] * * Common code for IShellFolder_BindToObject. * * PARAMS * pidlRoot [I] The parent shell folder's absolute pidl. * pathRoot [I] Absolute dos path of the parent shell folder. * pidlComplete [I] PIDL of the child. Relative to pidlRoot. * riid [I] GUID of the interface, which ppvOut shall be bound to. * ppvOut [O] A reference to the child's interface (riid). * * NOTES * pidlComplete has to contain at least one non empty SHITEMID. * This function makes special assumptions on the shell namespace, which * means you probably can't use it for your IShellFolder implementation. */ HRESULT SHELL32_BindToChild (LPCITEMIDLIST pidlRoot, LPCWSTR pathRoot, LPCITEMIDLIST pidlComplete, REFIID riid, LPVOID * ppvOut) { GUID const *clsid; IShellFolder *pSF; HRESULT hr; LPITEMIDLIST pidlChild; TRACE("(%p %s %p %s %p)\n", pidlRoot, debugstr_w(pathRoot), pidlComplete, debugstr_guid(riid), ppvOut); if (!pidlRoot || !ppvOut || _ILIsEmpty(pidlComplete)) return E_INVALIDARG; *ppvOut = NULL; pidlChild = ILCloneFirst (pidlComplete); if ((clsid = _ILGetGUIDPointer (pidlChild))) { /* virtual folder */ hr = SHELL32_CoCreateInitSF (pidlRoot, pathRoot, pidlChild, clsid, (LPVOID *)&pSF); } else if (_ILIsValue(pidlChild)) { /* Don't bind to files */ hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); } else { /* file system folder */ CLSID clsidFolder = CLSID_ShellFSFolder; static const WCHAR wszCLSID[] = {'C','L','S','I','D',0}; WCHAR wszCLSIDValue[CHARS_IN_GUID], wszFolderPath[MAX_PATH], *pwszPathTail = wszFolderPath; /* see if folder CLSID should be overridden by desktop.ini file */ if (pathRoot) { lstrcpynW(wszFolderPath, pathRoot, MAX_PATH); pwszPathTail = PathAddBackslashW(wszFolderPath); } _ILSimpleGetTextW(pidlChild,pwszPathTail,MAX_PATH - (int)(pwszPathTail - wszFolderPath)); if (SHELL32_GetCustomFolderAttributeFromPath (wszFolderPath, wszDotShellClassInfo, wszCLSID, wszCLSIDValue, CHARS_IN_GUID)) CLSIDFromString (wszCLSIDValue, &clsidFolder); hr = SHELL32_CoCreateInitSF (pidlRoot, pathRoot, pidlChild, &clsidFolder, (LPVOID *)&pSF); } ILFree (pidlChild); if (SUCCEEDED (hr)) { if (_ILIsPidlSimple (pidlComplete)) { /* no sub folders */ hr = IShellFolder_QueryInterface (pSF, riid, ppvOut); } else { /* go deeper */ hr = IShellFolder_BindToObject (pSF, ILGetNext (pidlComplete), NULL, riid, ppvOut); } IShellFolder_Release (pSF); } TRACE ("-- returning (%p) 0x%08x\n", *ppvOut, hr); return hr; }
static void update_path_box(explorer_info *info) { COMBOBOXEXITEMW item; COMBOBOXEXITEMW main_item; IShellFolder *desktop; IPersistFolder2 *persist; LPITEMIDLIST desktop_pidl; IEnumIDList *ids; ImageList_Remove((HIMAGELIST)info->icon_list,-1); SendMessageW(info->path_box,CB_RESETCONTENT,0,0); SHGetDesktopFolder(&desktop); IShellFolder_QueryInterface(desktop,&IID_IPersistFolder2,(void**)&persist); IPersistFolder2_GetCurFolder(persist,&desktop_pidl); IPersistFolder2_Release(persist); persist = NULL; /*Add Desktop*/ item.iItem = -1; item.mask = CBEIF_TEXT | CBEIF_INDENT | CBEIF_LPARAM; item.iIndent = 0; create_combobox_item(desktop,desktop_pidl,info->icon_list,&item); item.lParam = (LPARAM)desktop_pidl; SendMessageW(info->path_box,CBEM_INSERTITEMW,0,(LPARAM)&item); if(ILIsEqual(info->pidl,desktop_pidl)) main_item = item; else CoTaskMemFree(item.pszText); /*Add all direct subfolders of Desktop*/ if(SUCCEEDED(IShellFolder_EnumObjects(desktop,NULL,SHCONTF_FOLDERS,&ids)) && ids!=NULL) { LPITEMIDLIST curr_pidl=NULL; HRESULT hres; item.iIndent = 1; while(1) { ILFree(curr_pidl); curr_pidl=NULL; hres = IEnumIDList_Next(ids,1,&curr_pidl,NULL); if(FAILED(hres) || hres == S_FALSE) break; if(!create_combobox_item(desktop,curr_pidl,info->icon_list,&item)) WINE_WARN("Could not create a combobox item\n"); else { LPITEMIDLIST full_pidl = ILCombine(desktop_pidl,curr_pidl); item.lParam = (LPARAM)full_pidl; SendMessageW(info->path_box,CBEM_INSERTITEMW,0,(LPARAM)&item); if(ILIsEqual(full_pidl,info->pidl)) main_item = item; else if(ILIsParent(full_pidl,info->pidl,FALSE)) { /*add all parents of the pidl passed in*/ LPITEMIDLIST next_pidl = ILFindChild(full_pidl,info->pidl); IShellFolder *curr_folder = NULL, *temp; hres = IShellFolder_BindToObject(desktop,curr_pidl,NULL, &IID_IShellFolder, (void**)&curr_folder); if(FAILED(hres)) WINE_WARN("Could not get an IShellFolder\n"); while(!ILIsEmpty(next_pidl)) { LPITEMIDLIST first = ILCloneFirst(next_pidl); CoTaskMemFree(item.pszText); if(!create_combobox_item(curr_folder,first, info->icon_list,&item)) { WINE_WARN("Could not create a combobox item\n"); break; } ++item.iIndent; full_pidl = ILCombine(full_pidl,first); item.lParam = (LPARAM)full_pidl; SendMessageW(info->path_box,CBEM_INSERTITEMW,0,(LPARAM)&item); temp=NULL; hres = IShellFolder_BindToObject(curr_folder,first,NULL, &IID_IShellFolder, (void**)&temp); if(FAILED(hres)) { WINE_WARN("Could not get an IShellFolder\n"); break; } IShellFolder_Release(curr_folder); curr_folder = temp; ILFree(first); next_pidl = ILGetNext(next_pidl); } memcpy(&main_item,&item,sizeof(item)); if(curr_folder) IShellFolder_Release(curr_folder); item.iIndent = 1; } else CoTaskMemFree(item.pszText); } } ILFree(curr_pidl); IEnumIDList_Release(ids); } else WINE_WARN("Could not enumerate the desktop\n"); SendMessageW(info->path_box,CBEM_SETITEMW,0,(LPARAM)&main_item); CoTaskMemFree(main_item.pszText); }